From 4a3e24236f5ce466be7b64cd5393ab2bd1c9ac54 Mon Sep 17 00:00:00 2001 From: Mike Phares Date: Sun, 8 May 2022 12:28:50 -0700 Subject: [PATCH] Init --- .editorconfig | 243 +++ .gitattributes | 2 + .gitignore | 461 +++++ .txt | 10 + .vscode/launch.json | 28 + .vscode/settings.json | 11 + .vscode/tasks.json | 17 + Compare/.vscode/format-report.json | 1 + Compare/.vscode/launch.json | 32 + Compare/.vscode/settings.json | 14 + Compare/.vscode/tasks.json | 42 + Compare/Compare.cs | 906 ++++++++++ Compare/Compare.csproj | 67 + Compare/Models/AppSettings.cs | 35 + Compare/Models/Binder/AppSettings.cs | 26 + Compare/Models/Binder/Configuration.cs | 30 + Compare/Models/Configuration.cs | 43 + Compare/Models/Stateless/AppSettings.cs | 40 + Compare/Models/Stateless/Configuration.cs | 44 + .../Stateless/SerilogExtensionMethods.cs | 10 + Compare/Program.cs | 71 + Compare/appsettings.Development.json | 1609 +++++++++++++++++ Compare/appsettings.json | 1609 +++++++++++++++++ Date-Group/.vscode/format-report.json | 1 + Date-Group/.vscode/launch.json | 30 + Date-Group/.vscode/settings.json | 11 + Date-Group/.vscode/tasks.json | 42 + Date-Group/Date-Group.csproj | 63 + Date-Group/DateGroup.cs | 426 +++++ Date-Group/Models/AppSettings.cs | 35 + Date-Group/Models/Binder/AppSettings.cs | 26 + Date-Group/Models/Binder/Configuration.cs | 30 + Date-Group/Models/Configuration.cs | 43 + Date-Group/Models/Stateless/AppSettings.cs | 40 + Date-Group/Models/Stateless/Configuration.cs | 44 + .../Stateless/SerilogExtensionMethods.cs | 10 + Date-Group/Program.cs | 109 ++ Date-Group/appsettings.Development.json | 342 ++++ Instance/.vscode/format-report.json | 1 + Instance/.vscode/launch.json | 32 + Instance/.vscode/settings.json | 14 + Instance/.vscode/tasks.json | 42 + Instance/DlibDotNet.cs | 796 ++++++++ Instance/Instance.csproj | 92 + Instance/Models/AppSettings.cs | 35 + Instance/Models/Binder/AppSettings.cs | 26 + Instance/Models/Binder/Configuration.cs | 99 + Instance/Models/Configuration.cs | 145 ++ Instance/Models/Stateless/AppSettings.cs | 40 + Instance/Models/Stateless/Configuration.cs | 44 + .../Stateless/SerilogExtensionMethods.cs | 10 + Instance/Models/_A2_People.cs | 79 + Instance/Models/_D2_FaceLandmark.cs | 161 ++ Instance/Models/_D_Face.cs | 498 +++++ Instance/Models/_E2_Navigate.cs | 230 +++ Instance/Models/_E3_Rename.cs | 338 ++++ Instance/Models/_E_Distance.cs | 390 ++++ Instance/Models/_F_Random.cs | 90 + Instance/Models/_G2_Identify.cs | 229 +++ Instance/Models/_G_Index.cs | 213 +++ Instance/Program.cs | 71 + Instance/appsettings.Development.json | 457 +++++ Instance/appsettings.Staging.json | 457 +++++ Instance/appsettings.json | 458 +++++ Metadata/.vscode/settings.json | 7 + Metadata/Metadata.csproj | 47 + Metadata/Models/B_Metadata.cs | 181 ++ .../Stateless/SerilogExtensionMethods.cs | 10 + Not-Copy-Copy/.vscode/format-report.json | 1 + Not-Copy-Copy/.vscode/launch.json | 30 + Not-Copy-Copy/.vscode/settings.json | 11 + Not-Copy-Copy/.vscode/tasks.json | 42 + Not-Copy-Copy/Models/AppSettings.cs | 35 + Not-Copy-Copy/Models/Binder/AppSettings.cs | 26 + Not-Copy-Copy/Models/Binder/Configuration.cs | 27 + Not-Copy-Copy/Models/Configuration.cs | 43 + Not-Copy-Copy/Models/Stateless/AppSettings.cs | 40 + .../Models/Stateless/Configuration.cs | 44 + .../Stateless/SerilogExtensionMethods.cs | 10 + Not-Copy-Copy/Not-Copy-Copy.cs | 193 ++ Not-Copy-Copy/Not-Copy-Copy.csproj | 63 + Not-Copy-Copy/Program.cs | 127 ++ Not-Copy-Copy/appsettings.Development.json | 339 ++++ PrepareForOld/.vscode/format-report.json | 1 + PrepareForOld/.vscode/launch.json | 30 + PrepareForOld/.vscode/settings.json | 14 + PrepareForOld/.vscode/tasks.json | 42 + PrepareForOld/Models/AppSettings.cs | 35 + PrepareForOld/Models/Binder/AppSettings.cs | 26 + PrepareForOld/Models/Binder/Configuration.cs | 20 + PrepareForOld/Models/Configuration.cs | 31 + .../SaveTabSeparatedValues/ImageExifInfo.cs | 17 + .../SaveTabSeparatedValues/IndexInfo.cs | 8 + PrepareForOld/Models/Stateless/AppSettings.cs | 40 + .../Models/Stateless/Configuration.cs | 44 + .../Stateless/SerilogExtensionMethods.cs | 10 + PrepareForOld/PrepareForOld.cs | 666 +++++++ PrepareForOld/PrepareForOld.csproj | 60 + PrepareForOld/Program.cs | 71 + PrepareForOld/appsettings.Development.json | 364 ++++ Property-Compare/.vscode/format-report.json | 1 + Property-Compare/.vscode/settings.json | 8 + Property-Compare/Models/PropertyCompare.cs | 56 + .../Models/PropertyCompareItem.cs | 31 + .../Models/PropertyCompareLogic.cs | 609 +++++++ .../Stateless/SerilogExtensionMethods.cs | 10 + Property-Compare/Property-Compare.csproj | 48 + Property/.vscode/format-report.json | 1 + Property/.vscode/settings.json | 8 + Property/Models/A_Property.cs | 123 ++ Property/Models/Binder/Configuration.cs | 48 + Property/Models/Configuration.cs | 101 ++ Property/Models/Group.cs | 32 + Property/Models/PropertyLogic.cs | 780 ++++++++ Property/Models/Stateless/A_Property.cs | 377 ++++ Property/Models/Stateless/Configuration.cs | 42 + Property/Models/Stateless/IPath.cs | 24 + Property/Models/Stateless/IResult.cs | 24 + Property/Models/Stateless/Path.cs | 143 ++ Property/Models/Stateless/Result.cs | 98 + .../Stateless/SerilogExtensionMethods.cs | 10 + Property/Property.csproj | 58 + Resize/.vscode/format-report.json | 1 + Resize/.vscode/settings.json | 8 + .../Stateless/SerilogExtensionMethods.cs | 10 + Resize/Models/_C_Resize.cs | 534 ++++++ Resize/Resize.csproj | 49 + Shared/.vscode/settings.json | 5 + Shared/Models/%ClassName%.cs .ai | 0 Shared/Models/Console.cs | 27 + Shared/Models/DirectoryFileSystem.cs | 46 + Shared/Models/Face.cs | 57 + Shared/Models/FaceEncoding.cs | 28 + Shared/Models/FaceFileSystem.cs | 226 +++ Shared/Models/FacePoint.cs | 31 + Shared/Models/FileSystem.cs | 54 + Shared/Models/Location.cs | 37 + Shared/Models/MetadataFile.cs | 32 + Shared/Models/MetadataFileCollection.cs | 25 + Shared/Models/MetadataFileId.cs | 25 + Shared/Models/Methods/I%ClassName%.cs .ai | 0 Shared/Models/Methods/IBackground.cs | 12 + Shared/Models/Methods/IConfiguration.cs | 6 + Shared/Models/Methods/IConsole.cs | 9 + Shared/Models/Methods/IFace.cs | 8 + Shared/Models/Methods/IFaceEncoding.cs | 6 + Shared/Models/Methods/IFaceFileSystem.cs | 8 + Shared/Models/Methods/IFacePoint.cs | 6 + Shared/Models/Methods/IFileSystem.cs | 8 + Shared/Models/Methods/IIdentify.cs | 6 + Shared/Models/Methods/IIndex.cs | 8 + Shared/Models/Methods/ILocation.cs | 6 + Shared/Models/Methods/IMetadataFile.cs | 8 + .../Models/Methods/IMetadataFileCollection.cs | 8 + Shared/Models/Methods/IMetadataFileId.cs | 8 + Shared/Models/Methods/INavigate.cs | 6 + Shared/Models/Methods/IOutputResolution.cs | 6 + Shared/Models/Methods/IPerson.cs | 8 + Shared/Models/Methods/IPersonAddress.cs | 8 + Shared/Models/Methods/IPersonAddressCity.cs | 8 + Shared/Models/Methods/IPersonAddressState.cs | 8 + Shared/Models/Methods/IPersonAddressStreet.cs | 8 + .../Models/Methods/IPersonAddressZipCode.cs | 8 + Shared/Models/Methods/IPersonBirthday.cs | 8 + Shared/Models/Methods/IPersonComment.cs | 8 + Shared/Models/Methods/IPersonEmail.cs | 8 + Shared/Models/Methods/IPersonId.cs | 8 + Shared/Models/Methods/IPersonName.cs | 8 + Shared/Models/Methods/IPersonNameAlias.cs | 8 + Shared/Models/Methods/IPersonNameFirst.cs | 8 + Shared/Models/Methods/IPersonNameLast.cs | 8 + Shared/Models/Methods/IPersonNameMiddle.cs | 8 + Shared/Models/Methods/IPersonNumber.cs | 8 + Shared/Models/Methods/IPersonURL.cs | 8 + Shared/Models/Methods/IProperty.cs | 6 + Shared/Models/Methods/IRelativePaths.cs | 6 + Shared/Models/Methods/IStorage.cs | 8 + Shared/Models/Navigate.cs | 39 + Shared/Models/OutputResolution.cs | 31 + Shared/Models/Person.cs | 56 + Shared/Models/PersonAddress.cs | 40 + Shared/Models/PersonAddressCity.cs | 25 + Shared/Models/PersonAddressState.cs | 25 + Shared/Models/PersonAddressStreet.cs | 25 + Shared/Models/PersonAddressZipCode.cs | 25 + Shared/Models/PersonBirthday.cs | 25 + Shared/Models/PersonComment.cs | 25 + Shared/Models/PersonEmail.cs | 25 + Shared/Models/PersonId.cs | 25 + Shared/Models/PersonImport.cs | 37 + Shared/Models/PersonName.cs | 40 + Shared/Models/PersonNameAlias.cs | 25 + Shared/Models/PersonNameFirst.cs | 25 + Shared/Models/PersonNameLast.cs | 25 + Shared/Models/PersonNameMiddle.cs | 25 + Shared/Models/PersonNumber.cs | 25 + Shared/Models/PersonURL.cs | 25 + Shared/Models/Properties/I%ClassName%.cs .ai | 0 Shared/Models/Properties/IBackground.cs | 6 + Shared/Models/Properties/IBackgroundPage.cs | 10 + Shared/Models/Properties/IConfiguration.cs | 45 + Shared/Models/Properties/IConsole.cs | 6 + .../Models/Properties/IDirectoryFileSystem.cs | 12 + Shared/Models/Properties/IFace.cs | 18 + Shared/Models/Properties/IFaceEncoding.cs | 9 + Shared/Models/Properties/IFaceFileSystem.cs | 30 + Shared/Models/Properties/IFacePoint.cs | 10 + Shared/Models/Properties/IFileSystem.cs | 12 + Shared/Models/Properties/IIdentify.cs | 12 + Shared/Models/Properties/IIndex.cs | 10 + Shared/Models/Properties/ILocation.cs | 12 + Shared/Models/Properties/IMetadataFile.cs | 9 + .../Properties/IMetadataFileCollection.cs | 8 + Shared/Models/Properties/IMetadataFileId.cs | 8 + Shared/Models/Properties/INavigate.cs | 12 + Shared/Models/Properties/IOutputResolution.cs | 10 + Shared/Models/Properties/IPerson.cs | 15 + Shared/Models/Properties/IPersonAddress.cs | 11 + .../Models/Properties/IPersonAddressCity.cs | 8 + .../Models/Properties/IPersonAddressState.cs | 8 + .../Models/Properties/IPersonAddressStreet.cs | 8 + .../Properties/IPersonAddressZipCode.cs | 8 + Shared/Models/Properties/IPersonBirthday.cs | 8 + Shared/Models/Properties/IPersonComment.cs | 8 + Shared/Models/Properties/IPersonEmail.cs | 8 + Shared/Models/Properties/IPersonId.cs | 8 + Shared/Models/Properties/IPersonName.cs | 11 + Shared/Models/Properties/IPersonNameAlias.cs | 8 + Shared/Models/Properties/IPersonNameFirst.cs | 8 + Shared/Models/Properties/IPersonNameLast.cs | 8 + Shared/Models/Properties/IPersonNameMiddle.cs | 8 + Shared/Models/Properties/IPersonNumber.cs | 8 + Shared/Models/Properties/IPersonURL.cs | 8 + Shared/Models/Properties/IProperty.cs | 21 + Shared/Models/Properties/IRelativePaths.cs | 8 + Shared/Models/Properties/IRenamePage.cs | 6 + Shared/Models/Properties/IStorage.cs | 16 + Shared/Models/Property.cs | 72 + Shared/Models/RelativePaths.cs | 28 + Shared/Models/Stateless/IExif.cs | 148 ++ .../Stateless/Methods/%ClassName%.cs .ai | 0 Shared/Models/Stateless/Methods/Face.cs | 99 + .../Stateless/Methods/FaceFileSystem.cs | 83 + Shared/Models/Stateless/Methods/FileSystem.cs | 50 + .../Stateless/Methods/I%ClassName%.cs .ai | 0 .../Stateless/Methods/IBackgroundPage.cs | 10 + .../Stateless/Methods/IDirectoryFileSystem.cs | 6 + Shared/Models/Stateless/Methods/IFace.cs | 16 + .../Stateless/Methods/IFaceFileSystem.cs | 12 + .../Models/Stateless/Methods/IFileSystem.cs | 10 + Shared/Models/Stateless/Methods/IIndex.cs | 10 + .../Models/Stateless/Methods/IMetadataFile.cs | 8 + .../Methods/IMetadataFileCollection.cs | 12 + .../Stateless/Methods/IMetadataFileId.cs | 12 + .../Models/Stateless/Methods/IMethodName.cs | 10 + Shared/Models/Stateless/Methods/IPerson.cs | 23 + .../Stateless/Methods/IPersonAddress.cs | 8 + .../Stateless/Methods/IPersonAddressCity.cs | 12 + .../Stateless/Methods/IPersonAddressState.cs | 12 + .../Stateless/Methods/IPersonAddressStreet.cs | 12 + .../Methods/IPersonAddressZipCode.cs | 12 + .../Stateless/Methods/IPersonBirthday.cs | 30 + .../Stateless/Methods/IPersonComment.cs | 12 + .../Models/Stateless/Methods/IPersonEmail.cs | 12 + Shared/Models/Stateless/Methods/IPersonId.cs | 12 + .../Models/Stateless/Methods/IPersonName.cs | 8 + .../Stateless/Methods/IPersonNameAlias.cs | 12 + .../Stateless/Methods/IPersonNameFirst.cs | 12 + .../Stateless/Methods/IPersonNameLast.cs | 12 + .../Stateless/Methods/IPersonNameMiddle.cs | 12 + .../Models/Stateless/Methods/IPersonNumber.cs | 12 + Shared/Models/Stateless/Methods/IPersonURL.cs | 12 + Shared/Models/Stateless/Methods/IStorage.cs | 14 + .../Stateless/Methods/IWorkingDirectory.cs | 8 + .../Models/Stateless/Methods/ImageHelper.cs | 130 ++ Shared/Models/Stateless/Methods/Index.cs | 31 + .../Models/Stateless/Methods/MetadataFile.cs | 8 + .../Methods/MetadataFileCollection.cs | 10 + .../Stateless/Methods/MetadataFileId.cs | 10 + Shared/Models/Stateless/Methods/Person.cs | 229 +++ .../Models/Stateless/Methods/PersonAddress.cs | 8 + .../Stateless/Methods/PersonAddressCity.cs | 10 + .../Stateless/Methods/PersonAddressState.cs | 10 + .../Stateless/Methods/PersonAddressStreet.cs | 10 + .../Stateless/Methods/PersonAddressZipCode.cs | 10 + .../Stateless/Methods/PersonBirthday.cs | 16 + .../Models/Stateless/Methods/PersonComment.cs | 10 + .../Models/Stateless/Methods/PersonEmail.cs | 10 + Shared/Models/Stateless/Methods/PersonId.cs | 10 + Shared/Models/Stateless/Methods/PersonName.cs | 60 + .../Stateless/Methods/PersonNameAlias.cs | 10 + .../Stateless/Methods/PersonNameFirst.cs | 10 + .../Stateless/Methods/PersonNameLast.cs | 10 + .../Stateless/Methods/PersonNameMiddle.cs | 10 + .../Models/Stateless/Methods/PersonNumber.cs | 10 + Shared/Models/Stateless/Methods/PersonURL.cs | 10 + Shared/Models/Stateless/Methods/Storage.cs | 27 + .../Stateless/Methods/WorkingDirectory.cs | 50 + Shared/Models/Storage.cs | 79 + Shared/Phares/Shared/IsEnvironment.cs | 167 ++ Shared/Phares/Shared/RijndaelEncryption.cs | 93 + Shared/Sample-Data/MetadataFile.cs | 1 + Shared/Sample-Data/People.cs | 1 + Shared/Sample-Data/PropertyCollectionFile.cs | 1 + Shared/Sample-Data/metadataFile.json | 80 + Shared/Sample-Data/metadataFiles.json | 18 + Shared/Sample-Data/people.json | 63 + Shared/Sample-Data/person.json | 576 ++++++ .../Sample-Data/propertyCollectionFile.json | 80 + .../Sample-Data/propertyCollectionFiles.json | 22 + Shared/View-by-Distance.Shared.csproj | 40 + View-by-Distance-MKLink-Console.sln | 76 + package.json | 17 + 313 files changed, 22395 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .txt create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json create mode 100644 Compare/.vscode/format-report.json create mode 100644 Compare/.vscode/launch.json create mode 100644 Compare/.vscode/settings.json create mode 100644 Compare/.vscode/tasks.json create mode 100644 Compare/Compare.cs create mode 100644 Compare/Compare.csproj create mode 100644 Compare/Models/AppSettings.cs create mode 100644 Compare/Models/Binder/AppSettings.cs create mode 100644 Compare/Models/Binder/Configuration.cs create mode 100644 Compare/Models/Configuration.cs create mode 100644 Compare/Models/Stateless/AppSettings.cs create mode 100644 Compare/Models/Stateless/Configuration.cs create mode 100644 Compare/Models/Stateless/SerilogExtensionMethods.cs create mode 100644 Compare/Program.cs create mode 100644 Compare/appsettings.Development.json create mode 100644 Compare/appsettings.json create mode 100644 Date-Group/.vscode/format-report.json create mode 100644 Date-Group/.vscode/launch.json create mode 100644 Date-Group/.vscode/settings.json create mode 100644 Date-Group/.vscode/tasks.json create mode 100644 Date-Group/Date-Group.csproj create mode 100644 Date-Group/DateGroup.cs create mode 100644 Date-Group/Models/AppSettings.cs create mode 100644 Date-Group/Models/Binder/AppSettings.cs create mode 100644 Date-Group/Models/Binder/Configuration.cs create mode 100644 Date-Group/Models/Configuration.cs create mode 100644 Date-Group/Models/Stateless/AppSettings.cs create mode 100644 Date-Group/Models/Stateless/Configuration.cs create mode 100644 Date-Group/Models/Stateless/SerilogExtensionMethods.cs create mode 100644 Date-Group/Program.cs create mode 100644 Date-Group/appsettings.Development.json create mode 100644 Instance/.vscode/format-report.json create mode 100644 Instance/.vscode/launch.json create mode 100644 Instance/.vscode/settings.json create mode 100644 Instance/.vscode/tasks.json create mode 100644 Instance/DlibDotNet.cs create mode 100644 Instance/Instance.csproj create mode 100644 Instance/Models/AppSettings.cs create mode 100644 Instance/Models/Binder/AppSettings.cs create mode 100644 Instance/Models/Binder/Configuration.cs create mode 100644 Instance/Models/Configuration.cs create mode 100644 Instance/Models/Stateless/AppSettings.cs create mode 100644 Instance/Models/Stateless/Configuration.cs create mode 100644 Instance/Models/Stateless/SerilogExtensionMethods.cs create mode 100644 Instance/Models/_A2_People.cs create mode 100644 Instance/Models/_D2_FaceLandmark.cs create mode 100644 Instance/Models/_D_Face.cs create mode 100644 Instance/Models/_E2_Navigate.cs create mode 100644 Instance/Models/_E3_Rename.cs create mode 100644 Instance/Models/_E_Distance.cs create mode 100644 Instance/Models/_F_Random.cs create mode 100644 Instance/Models/_G2_Identify.cs create mode 100644 Instance/Models/_G_Index.cs create mode 100644 Instance/Program.cs create mode 100644 Instance/appsettings.Development.json create mode 100644 Instance/appsettings.Staging.json create mode 100644 Instance/appsettings.json create mode 100644 Metadata/.vscode/settings.json create mode 100644 Metadata/Metadata.csproj create mode 100644 Metadata/Models/B_Metadata.cs create mode 100644 Metadata/Models/Stateless/SerilogExtensionMethods.cs create mode 100644 Not-Copy-Copy/.vscode/format-report.json create mode 100644 Not-Copy-Copy/.vscode/launch.json create mode 100644 Not-Copy-Copy/.vscode/settings.json create mode 100644 Not-Copy-Copy/.vscode/tasks.json create mode 100644 Not-Copy-Copy/Models/AppSettings.cs create mode 100644 Not-Copy-Copy/Models/Binder/AppSettings.cs create mode 100644 Not-Copy-Copy/Models/Binder/Configuration.cs create mode 100644 Not-Copy-Copy/Models/Configuration.cs create mode 100644 Not-Copy-Copy/Models/Stateless/AppSettings.cs create mode 100644 Not-Copy-Copy/Models/Stateless/Configuration.cs create mode 100644 Not-Copy-Copy/Models/Stateless/SerilogExtensionMethods.cs create mode 100644 Not-Copy-Copy/Not-Copy-Copy.cs create mode 100644 Not-Copy-Copy/Not-Copy-Copy.csproj create mode 100644 Not-Copy-Copy/Program.cs create mode 100644 Not-Copy-Copy/appsettings.Development.json create mode 100644 PrepareForOld/.vscode/format-report.json create mode 100644 PrepareForOld/.vscode/launch.json create mode 100644 PrepareForOld/.vscode/settings.json create mode 100644 PrepareForOld/.vscode/tasks.json create mode 100644 PrepareForOld/Models/AppSettings.cs create mode 100644 PrepareForOld/Models/Binder/AppSettings.cs create mode 100644 PrepareForOld/Models/Binder/Configuration.cs create mode 100644 PrepareForOld/Models/Configuration.cs create mode 100644 PrepareForOld/Models/SaveTabSeparatedValues/ImageExifInfo.cs create mode 100644 PrepareForOld/Models/SaveTabSeparatedValues/IndexInfo.cs create mode 100644 PrepareForOld/Models/Stateless/AppSettings.cs create mode 100644 PrepareForOld/Models/Stateless/Configuration.cs create mode 100644 PrepareForOld/Models/Stateless/SerilogExtensionMethods.cs create mode 100644 PrepareForOld/PrepareForOld.cs create mode 100644 PrepareForOld/PrepareForOld.csproj create mode 100644 PrepareForOld/Program.cs create mode 100644 PrepareForOld/appsettings.Development.json create mode 100644 Property-Compare/.vscode/format-report.json create mode 100644 Property-Compare/.vscode/settings.json create mode 100644 Property-Compare/Models/PropertyCompare.cs create mode 100644 Property-Compare/Models/PropertyCompareItem.cs create mode 100644 Property-Compare/Models/PropertyCompareLogic.cs create mode 100644 Property-Compare/Models/Stateless/SerilogExtensionMethods.cs create mode 100644 Property-Compare/Property-Compare.csproj create mode 100644 Property/.vscode/format-report.json create mode 100644 Property/.vscode/settings.json create mode 100644 Property/Models/A_Property.cs create mode 100644 Property/Models/Binder/Configuration.cs create mode 100644 Property/Models/Configuration.cs create mode 100644 Property/Models/Group.cs create mode 100644 Property/Models/PropertyLogic.cs create mode 100644 Property/Models/Stateless/A_Property.cs create mode 100644 Property/Models/Stateless/Configuration.cs create mode 100644 Property/Models/Stateless/IPath.cs create mode 100644 Property/Models/Stateless/IResult.cs create mode 100644 Property/Models/Stateless/Path.cs create mode 100644 Property/Models/Stateless/Result.cs create mode 100644 Property/Models/Stateless/SerilogExtensionMethods.cs create mode 100644 Property/Property.csproj create mode 100644 Resize/.vscode/format-report.json create mode 100644 Resize/.vscode/settings.json create mode 100644 Resize/Models/Stateless/SerilogExtensionMethods.cs create mode 100644 Resize/Models/_C_Resize.cs create mode 100644 Resize/Resize.csproj create mode 100644 Shared/.vscode/settings.json create mode 100644 Shared/Models/%ClassName%.cs .ai create mode 100644 Shared/Models/Console.cs create mode 100644 Shared/Models/DirectoryFileSystem.cs create mode 100644 Shared/Models/Face.cs create mode 100644 Shared/Models/FaceEncoding.cs create mode 100644 Shared/Models/FaceFileSystem.cs create mode 100644 Shared/Models/FacePoint.cs create mode 100644 Shared/Models/FileSystem.cs create mode 100644 Shared/Models/Location.cs create mode 100644 Shared/Models/MetadataFile.cs create mode 100644 Shared/Models/MetadataFileCollection.cs create mode 100644 Shared/Models/MetadataFileId.cs create mode 100644 Shared/Models/Methods/I%ClassName%.cs .ai create mode 100644 Shared/Models/Methods/IBackground.cs create mode 100644 Shared/Models/Methods/IConfiguration.cs create mode 100644 Shared/Models/Methods/IConsole.cs create mode 100644 Shared/Models/Methods/IFace.cs create mode 100644 Shared/Models/Methods/IFaceEncoding.cs create mode 100644 Shared/Models/Methods/IFaceFileSystem.cs create mode 100644 Shared/Models/Methods/IFacePoint.cs create mode 100644 Shared/Models/Methods/IFileSystem.cs create mode 100644 Shared/Models/Methods/IIdentify.cs create mode 100644 Shared/Models/Methods/IIndex.cs create mode 100644 Shared/Models/Methods/ILocation.cs create mode 100644 Shared/Models/Methods/IMetadataFile.cs create mode 100644 Shared/Models/Methods/IMetadataFileCollection.cs create mode 100644 Shared/Models/Methods/IMetadataFileId.cs create mode 100644 Shared/Models/Methods/INavigate.cs create mode 100644 Shared/Models/Methods/IOutputResolution.cs create mode 100644 Shared/Models/Methods/IPerson.cs create mode 100644 Shared/Models/Methods/IPersonAddress.cs create mode 100644 Shared/Models/Methods/IPersonAddressCity.cs create mode 100644 Shared/Models/Methods/IPersonAddressState.cs create mode 100644 Shared/Models/Methods/IPersonAddressStreet.cs create mode 100644 Shared/Models/Methods/IPersonAddressZipCode.cs create mode 100644 Shared/Models/Methods/IPersonBirthday.cs create mode 100644 Shared/Models/Methods/IPersonComment.cs create mode 100644 Shared/Models/Methods/IPersonEmail.cs create mode 100644 Shared/Models/Methods/IPersonId.cs create mode 100644 Shared/Models/Methods/IPersonName.cs create mode 100644 Shared/Models/Methods/IPersonNameAlias.cs create mode 100644 Shared/Models/Methods/IPersonNameFirst.cs create mode 100644 Shared/Models/Methods/IPersonNameLast.cs create mode 100644 Shared/Models/Methods/IPersonNameMiddle.cs create mode 100644 Shared/Models/Methods/IPersonNumber.cs create mode 100644 Shared/Models/Methods/IPersonURL.cs create mode 100644 Shared/Models/Methods/IProperty.cs create mode 100644 Shared/Models/Methods/IRelativePaths.cs create mode 100644 Shared/Models/Methods/IStorage.cs create mode 100644 Shared/Models/Navigate.cs create mode 100644 Shared/Models/OutputResolution.cs create mode 100644 Shared/Models/Person.cs create mode 100644 Shared/Models/PersonAddress.cs create mode 100644 Shared/Models/PersonAddressCity.cs create mode 100644 Shared/Models/PersonAddressState.cs create mode 100644 Shared/Models/PersonAddressStreet.cs create mode 100644 Shared/Models/PersonAddressZipCode.cs create mode 100644 Shared/Models/PersonBirthday.cs create mode 100644 Shared/Models/PersonComment.cs create mode 100644 Shared/Models/PersonEmail.cs create mode 100644 Shared/Models/PersonId.cs create mode 100644 Shared/Models/PersonImport.cs create mode 100644 Shared/Models/PersonName.cs create mode 100644 Shared/Models/PersonNameAlias.cs create mode 100644 Shared/Models/PersonNameFirst.cs create mode 100644 Shared/Models/PersonNameLast.cs create mode 100644 Shared/Models/PersonNameMiddle.cs create mode 100644 Shared/Models/PersonNumber.cs create mode 100644 Shared/Models/PersonURL.cs create mode 100644 Shared/Models/Properties/I%ClassName%.cs .ai create mode 100644 Shared/Models/Properties/IBackground.cs create mode 100644 Shared/Models/Properties/IBackgroundPage.cs create mode 100644 Shared/Models/Properties/IConfiguration.cs create mode 100644 Shared/Models/Properties/IConsole.cs create mode 100644 Shared/Models/Properties/IDirectoryFileSystem.cs create mode 100644 Shared/Models/Properties/IFace.cs create mode 100644 Shared/Models/Properties/IFaceEncoding.cs create mode 100644 Shared/Models/Properties/IFaceFileSystem.cs create mode 100644 Shared/Models/Properties/IFacePoint.cs create mode 100644 Shared/Models/Properties/IFileSystem.cs create mode 100644 Shared/Models/Properties/IIdentify.cs create mode 100644 Shared/Models/Properties/IIndex.cs create mode 100644 Shared/Models/Properties/ILocation.cs create mode 100644 Shared/Models/Properties/IMetadataFile.cs create mode 100644 Shared/Models/Properties/IMetadataFileCollection.cs create mode 100644 Shared/Models/Properties/IMetadataFileId.cs create mode 100644 Shared/Models/Properties/INavigate.cs create mode 100644 Shared/Models/Properties/IOutputResolution.cs create mode 100644 Shared/Models/Properties/IPerson.cs create mode 100644 Shared/Models/Properties/IPersonAddress.cs create mode 100644 Shared/Models/Properties/IPersonAddressCity.cs create mode 100644 Shared/Models/Properties/IPersonAddressState.cs create mode 100644 Shared/Models/Properties/IPersonAddressStreet.cs create mode 100644 Shared/Models/Properties/IPersonAddressZipCode.cs create mode 100644 Shared/Models/Properties/IPersonBirthday.cs create mode 100644 Shared/Models/Properties/IPersonComment.cs create mode 100644 Shared/Models/Properties/IPersonEmail.cs create mode 100644 Shared/Models/Properties/IPersonId.cs create mode 100644 Shared/Models/Properties/IPersonName.cs create mode 100644 Shared/Models/Properties/IPersonNameAlias.cs create mode 100644 Shared/Models/Properties/IPersonNameFirst.cs create mode 100644 Shared/Models/Properties/IPersonNameLast.cs create mode 100644 Shared/Models/Properties/IPersonNameMiddle.cs create mode 100644 Shared/Models/Properties/IPersonNumber.cs create mode 100644 Shared/Models/Properties/IPersonURL.cs create mode 100644 Shared/Models/Properties/IProperty.cs create mode 100644 Shared/Models/Properties/IRelativePaths.cs create mode 100644 Shared/Models/Properties/IRenamePage.cs create mode 100644 Shared/Models/Properties/IStorage.cs create mode 100644 Shared/Models/Property.cs create mode 100644 Shared/Models/RelativePaths.cs create mode 100644 Shared/Models/Stateless/IExif.cs create mode 100644 Shared/Models/Stateless/Methods/%ClassName%.cs .ai create mode 100644 Shared/Models/Stateless/Methods/Face.cs create mode 100644 Shared/Models/Stateless/Methods/FaceFileSystem.cs create mode 100644 Shared/Models/Stateless/Methods/FileSystem.cs create mode 100644 Shared/Models/Stateless/Methods/I%ClassName%.cs .ai create mode 100644 Shared/Models/Stateless/Methods/IBackgroundPage.cs create mode 100644 Shared/Models/Stateless/Methods/IDirectoryFileSystem.cs create mode 100644 Shared/Models/Stateless/Methods/IFace.cs create mode 100644 Shared/Models/Stateless/Methods/IFaceFileSystem.cs create mode 100644 Shared/Models/Stateless/Methods/IFileSystem.cs create mode 100644 Shared/Models/Stateless/Methods/IIndex.cs create mode 100644 Shared/Models/Stateless/Methods/IMetadataFile.cs create mode 100644 Shared/Models/Stateless/Methods/IMetadataFileCollection.cs create mode 100644 Shared/Models/Stateless/Methods/IMetadataFileId.cs create mode 100644 Shared/Models/Stateless/Methods/IMethodName.cs create mode 100644 Shared/Models/Stateless/Methods/IPerson.cs create mode 100644 Shared/Models/Stateless/Methods/IPersonAddress.cs create mode 100644 Shared/Models/Stateless/Methods/IPersonAddressCity.cs create mode 100644 Shared/Models/Stateless/Methods/IPersonAddressState.cs create mode 100644 Shared/Models/Stateless/Methods/IPersonAddressStreet.cs create mode 100644 Shared/Models/Stateless/Methods/IPersonAddressZipCode.cs create mode 100644 Shared/Models/Stateless/Methods/IPersonBirthday.cs create mode 100644 Shared/Models/Stateless/Methods/IPersonComment.cs create mode 100644 Shared/Models/Stateless/Methods/IPersonEmail.cs create mode 100644 Shared/Models/Stateless/Methods/IPersonId.cs create mode 100644 Shared/Models/Stateless/Methods/IPersonName.cs create mode 100644 Shared/Models/Stateless/Methods/IPersonNameAlias.cs create mode 100644 Shared/Models/Stateless/Methods/IPersonNameFirst.cs create mode 100644 Shared/Models/Stateless/Methods/IPersonNameLast.cs create mode 100644 Shared/Models/Stateless/Methods/IPersonNameMiddle.cs create mode 100644 Shared/Models/Stateless/Methods/IPersonNumber.cs create mode 100644 Shared/Models/Stateless/Methods/IPersonURL.cs create mode 100644 Shared/Models/Stateless/Methods/IStorage.cs create mode 100644 Shared/Models/Stateless/Methods/IWorkingDirectory.cs create mode 100644 Shared/Models/Stateless/Methods/ImageHelper.cs create mode 100644 Shared/Models/Stateless/Methods/Index.cs create mode 100644 Shared/Models/Stateless/Methods/MetadataFile.cs create mode 100644 Shared/Models/Stateless/Methods/MetadataFileCollection.cs create mode 100644 Shared/Models/Stateless/Methods/MetadataFileId.cs create mode 100644 Shared/Models/Stateless/Methods/Person.cs create mode 100644 Shared/Models/Stateless/Methods/PersonAddress.cs create mode 100644 Shared/Models/Stateless/Methods/PersonAddressCity.cs create mode 100644 Shared/Models/Stateless/Methods/PersonAddressState.cs create mode 100644 Shared/Models/Stateless/Methods/PersonAddressStreet.cs create mode 100644 Shared/Models/Stateless/Methods/PersonAddressZipCode.cs create mode 100644 Shared/Models/Stateless/Methods/PersonBirthday.cs create mode 100644 Shared/Models/Stateless/Methods/PersonComment.cs create mode 100644 Shared/Models/Stateless/Methods/PersonEmail.cs create mode 100644 Shared/Models/Stateless/Methods/PersonId.cs create mode 100644 Shared/Models/Stateless/Methods/PersonName.cs create mode 100644 Shared/Models/Stateless/Methods/PersonNameAlias.cs create mode 100644 Shared/Models/Stateless/Methods/PersonNameFirst.cs create mode 100644 Shared/Models/Stateless/Methods/PersonNameLast.cs create mode 100644 Shared/Models/Stateless/Methods/PersonNameMiddle.cs create mode 100644 Shared/Models/Stateless/Methods/PersonNumber.cs create mode 100644 Shared/Models/Stateless/Methods/PersonURL.cs create mode 100644 Shared/Models/Stateless/Methods/Storage.cs create mode 100644 Shared/Models/Stateless/Methods/WorkingDirectory.cs create mode 100644 Shared/Models/Storage.cs create mode 100644 Shared/Phares/Shared/IsEnvironment.cs create mode 100644 Shared/Phares/Shared/RijndaelEncryption.cs create mode 100644 Shared/Sample-Data/MetadataFile.cs create mode 100644 Shared/Sample-Data/People.cs create mode 100644 Shared/Sample-Data/PropertyCollectionFile.cs create mode 100644 Shared/Sample-Data/metadataFile.json create mode 100644 Shared/Sample-Data/metadataFiles.json create mode 100644 Shared/Sample-Data/people.json create mode 100644 Shared/Sample-Data/person.json create mode 100644 Shared/Sample-Data/propertyCollectionFile.json create mode 100644 Shared/Sample-Data/propertyCollectionFiles.json create mode 100644 Shared/View-by-Distance.Shared.csproj create mode 100644 View-by-Distance-MKLink-Console.sln create mode 100644 package.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..2656b69 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,243 @@ +[*.cs] +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = true +csharp_indent_labels = one_less_than_current +csharp_indent_switch_labels = true +csharp_new_line_before_catch = true +csharp_new_line_before_else = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_open_brace = all +csharp_new_line_between_query_expression_clauses = true +csharp_prefer_braces = false +csharp_prefer_qualified_reference = true:error +csharp_prefer_simple_default_expression = true:warning +csharp_prefer_simple_using_statement = true:warning +csharp_prefer_static_local_function = true:warning +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = false +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false +csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true +csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true +csharp_style_allow_embedded_statements_on_same_line_experimental = true +csharp_style_conditional_delegate_call = true +csharp_style_deconstructed_variable_declaration = false +csharp_style_expression_bodied_accessors = when_on_single_line:warning +csharp_style_expression_bodied_constructors = when_on_single_line:warning +csharp_style_expression_bodied_indexers = when_on_single_line:warning +csharp_style_expression_bodied_lambdas = when_on_single_line:warning +csharp_style_expression_bodied_local_functions = when_on_single_line:warning +csharp_style_expression_bodied_methods = when_on_single_line:warning +csharp_style_expression_bodied_operators = when_on_single_line:warning +csharp_style_expression_bodied_properties = when_on_single_line:warning +csharp_style_implicit_object_creation_when_type_is_apparent = true:warning +csharp_style_inlined_variable_declaration = false +csharp_style_namespace_declarations = file_scoped:warning +csharp_style_pattern_local_over_anonymous_function = true:warning +csharp_style_pattern_matching_over_as_with_null_check = true:warning +csharp_style_pattern_matching_over_is_with_cast_check = true:warning +csharp_style_prefer_index_operator = true:warning +csharp_style_prefer_not_pattern = true:warning +csharp_style_prefer_null_check_over_type_check = true +csharp_style_prefer_pattern_matching = true:warning +csharp_style_prefer_range_operator = true:warning +csharp_style_prefer_switch_expression = true:warning +csharp_style_throw_expression = true +csharp_style_unused_value_assignment_preference = discard_variable:warning +csharp_style_unused_value_expression_statement_preference = discard_variable:warning +csharp_style_var_elsewhere = false:warning +csharp_style_var_for_built_in_types = false:warning +csharp_style_var_when_type_is_apparent = false:warning +csharp_using_directive_placement = outside_namespace +dotnet_code_quality_unused_parameters = all +dotnet_code_quality_unused_parameters = non_public # IDE0060: Remove unused parameter +dotnet_code_quality.CAXXXX.api_surface = private, internal +dotnet_diagnostic.CA1825.severity = warning # CA1823: Avoid zero-length array allocations +dotnet_diagnostic.CA1829.severity = warning # CA1829: Use Length/Count property instead of Count() when available +dotnet_diagnostic.CA1834.severity = warning # CA1834: Consider using 'StringBuilder.Append(char)' when applicable +dotnet_diagnostic.IDE0001.severity = warning # IDE0001: Simplify name +dotnet_diagnostic.IDE0002.severity = warning # Simplify (member access) System.Version.Equals("1", "2"); Version.Equals("1", "2"); +dotnet_diagnostic.IDE0005.severity = warning # Using directive is unnecessary using System.Text; +dotnet_diagnostic.IDE0060.severity = warning # IDE0060: Remove unused parameter +dotnet_naming_rule.abstract_method_should_be_pascal_case.severity = warning +dotnet_naming_rule.abstract_method_should_be_pascal_case.style = pascal_case +dotnet_naming_rule.abstract_method_should_be_pascal_case.symbols = abstract_method +dotnet_naming_rule.class_should_be_pascal_case.severity = warning +dotnet_naming_rule.class_should_be_pascal_case.style = pascal_case +dotnet_naming_rule.class_should_be_pascal_case.symbols = class +dotnet_naming_rule.delegate_should_be_pascal_case.severity = warning +dotnet_naming_rule.delegate_should_be_pascal_case.style = pascal_case +dotnet_naming_rule.delegate_should_be_pascal_case.symbols = delegate +dotnet_naming_rule.enum_should_be_pascal_case.severity = warning +dotnet_naming_rule.enum_should_be_pascal_case.style = pascal_case +dotnet_naming_rule.enum_should_be_pascal_case.symbols = enum +dotnet_naming_rule.event_should_be_pascal_case.severity = warning +dotnet_naming_rule.event_should_be_pascal_case.style = pascal_case +dotnet_naming_rule.event_should_be_pascal_case.symbols = event +dotnet_naming_rule.interface_should_be_begins_with_i.severity = warning +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.method_should_be_pascal_case.severity = warning +dotnet_naming_rule.method_should_be_pascal_case.style = pascal_case +dotnet_naming_rule.method_should_be_pascal_case.symbols = method +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = warning +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.private_method_should_be_pascal_case.severity = warning +dotnet_naming_rule.private_method_should_be_pascal_case.style = pascal_case +dotnet_naming_rule.private_method_should_be_pascal_case.symbols = private_method +dotnet_naming_rule.private_or_internal_field_should_be_private_of_internal_field.severity = warning +dotnet_naming_rule.private_or_internal_field_should_be_private_of_internal_field.style = private_of_internal_field +dotnet_naming_rule.private_or_internal_field_should_be_private_of_internal_field.symbols = private_or_internal_field +dotnet_naming_rule.private_or_internal_static_field_should_be_private_of_internal_field.severity = warning +dotnet_naming_rule.private_or_internal_static_field_should_be_private_of_internal_field.style = private_of_internal_field +dotnet_naming_rule.private_or_internal_static_field_should_be_private_of_internal_field.symbols = private_or_internal_static_field +dotnet_naming_rule.property_should_be_pascal_case.severity = warning +dotnet_naming_rule.property_should_be_pascal_case.style = pascal_case +dotnet_naming_rule.property_should_be_pascal_case.symbols = property +dotnet_naming_rule.public_or_protected_field_should_be_private_of_internal_field.severity = warning +dotnet_naming_rule.public_or_protected_field_should_be_private_of_internal_field.style = private_of_internal_field +dotnet_naming_rule.public_or_protected_field_should_be_private_of_internal_field.symbols = public_or_protected_field +dotnet_naming_rule.static_field_should_be_pascal_case.severity = warning +dotnet_naming_rule.static_field_should_be_pascal_case.style = pascal_case +dotnet_naming_rule.static_field_should_be_pascal_case.symbols = static_field +dotnet_naming_rule.static_method_should_be_pascal_case.severity = warning +dotnet_naming_rule.static_method_should_be_pascal_case.style = pascal_case +dotnet_naming_rule.static_method_should_be_pascal_case.symbols = static_method +dotnet_naming_rule.struct_should_be_pascal_case.severity = warning +dotnet_naming_rule.struct_should_be_pascal_case.style = pascal_case +dotnet_naming_rule.struct_should_be_pascal_case.symbols = struct +dotnet_naming_rule.types_should_be_pascal_case.severity = warning +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_style.begins_with_i.capitalization = pascal_case +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.private_of_internal_field.capitalization = pascal_case +dotnet_naming_style.private_of_internal_field.required_prefix = _ +dotnet_naming_style.private_of_internal_field.required_suffix = +dotnet_naming_style.private_of_internal_field.word_separator = +dotnet_naming_symbols.abstract_method.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.abstract_method.applicable_kinds = method +dotnet_naming_symbols.abstract_method.required_modifiers = abstract +dotnet_naming_symbols.class.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.class.applicable_kinds = class +dotnet_naming_symbols.class.required_modifiers = +dotnet_naming_symbols.delegate.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.delegate.applicable_kinds = delegate +dotnet_naming_symbols.delegate.required_modifiers = +dotnet_naming_symbols.enum.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.enum.applicable_kinds = enum +dotnet_naming_symbols.enum.required_modifiers = +dotnet_naming_symbols.event.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.event.applicable_kinds = event +dotnet_naming_symbols.event.required_modifiers = +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.required_modifiers = +dotnet_naming_symbols.method.applicable_accessibilities = public +dotnet_naming_symbols.method.applicable_kinds = method +dotnet_naming_symbols.method.required_modifiers = +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.required_modifiers = +dotnet_naming_symbols.private_method.applicable_accessibilities = private +dotnet_naming_symbols.private_method.applicable_kinds = method +dotnet_naming_symbols.private_method.required_modifiers = +dotnet_naming_symbols.private_or_internal_field.applicable_accessibilities = internal, private, private_protected +dotnet_naming_symbols.private_or_internal_field.applicable_kinds = field +dotnet_naming_symbols.private_or_internal_field.required_modifiers = +dotnet_naming_symbols.private_or_internal_static_field.applicable_accessibilities = internal, private, private_protected +dotnet_naming_symbols.private_or_internal_static_field.applicable_kinds = field +dotnet_naming_symbols.private_or_internal_static_field.required_modifiers = static +dotnet_naming_symbols.property.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.property.applicable_kinds = property +dotnet_naming_symbols.property.required_modifiers = +dotnet_naming_symbols.public_or_protected_field.applicable_accessibilities = public, protected +dotnet_naming_symbols.public_or_protected_field.applicable_kinds = field +dotnet_naming_symbols.public_or_protected_field.required_modifiers = +dotnet_naming_symbols.static_field.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.static_field.applicable_kinds = field +dotnet_naming_symbols.static_field.required_modifiers = static +dotnet_naming_symbols.static_method.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.static_method.applicable_kinds = method +dotnet_naming_symbols.static_method.required_modifiers = static +dotnet_naming_symbols.struct.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.struct.applicable_kinds = struct +dotnet_naming_symbols.struct.required_modifiers = +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.required_modifiers = +dotnet_remove_unnecessary_suppression_exclusions = 0 +dotnet_separate_import_directive_groups = false +dotnet_sort_system_directives_first = false +dotnet_style_allow_multiple_blank_lines_experimental = false:warning +dotnet_style_allow_statement_immediately_after_block_experimental = true +dotnet_style_coalesce_expression = true +dotnet_style_collection_initializer = true:warning +dotnet_style_explicit_tuple_names = true:warning +dotnet_style_namespace_match_folder = true +dotnet_style_null_propagation = true:warning +dotnet_style_object_initializer = true:warning +dotnet_style_operator_placement_when_wrapping = beginning_of_line +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity +dotnet_style_parentheses_in_other_operators = never_if_unnecessary +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity +dotnet_style_predefined_type_for_locals_parameters_members = true +dotnet_style_predefined_type_for_member_access = true +dotnet_style_prefer_auto_properties = true:warning +dotnet_style_prefer_compound_assignment = true:warning +dotnet_style_prefer_conditional_expression_over_assignment = false +dotnet_style_prefer_conditional_expression_over_return = false +dotnet_style_prefer_inferred_anonymous_type_member_names = true:warning +dotnet_style_prefer_inferred_tuple_names = true:warning +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning +dotnet_style_prefer_simplified_boolean_expressions = true:warning +dotnet_style_prefer_simplified_interpolation = true +dotnet_style_qualification_for_event = false:error +dotnet_style_qualification_for_field = false +dotnet_style_qualification_for_method = false:error +dotnet_style_qualification_for_property = false:error +dotnet_style_readonly_field = true:warning +dotnet_style_require_accessibility_modifiers = for_non_interface_members +end_of_line = crlf +file_header_template = unset +indent_size = 4 +indent_style = space +insert_final_newline = false +root = true +tab_width = 4 +# https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1822 +# https://github.com/dotnet/aspnetcore/blob/main/.editorconfig +# https://github.com/dotnet/project-system/blob/main/.editorconfig \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dbce141 --- /dev/null +++ b/.gitignore @@ -0,0 +1,461 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# Tye +.tye/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +## +## Visual studio for Mac +## + + +# globs +Makefile.in +*.userprefs +*.usertasks +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.tar.gz +tarballs/ +test-results/ + +# Mac bundle stuff +*.dmg +*.app + +# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# JetBrains Rider +.idea/ +*.sln.iml + +## +## Visual Studio Code +## +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +#VSCode Settings => mklink /J "VSCode Settings" "C:\Users\phares\AppData\Roaming\Code\User" +globalStorage/ +*workspaceStorage/ + +#Auto Gen Code from Code-Generator +*.gen \ No newline at end of file diff --git a/.txt b/.txt new file mode 100644 index 0000000..a0b1096 --- /dev/null +++ b/.txt @@ -0,0 +1,10 @@ + mklink /J "L:\Git\View-by-Distance-MKLink-Console\Compare" "L:\Git\View-by-Distance\Compare" + mklink /J "L:\Git\View-by-Distance-MKLink-Console\Date-Group" "L:\Git\View-by-Distance\Date-Group" + mklink /J "L:\Git\View-by-Distance-MKLink-Console\Instance" "L:\Git\View-by-Distance\Instance" + mklink /J "L:\Git\View-by-Distance-MKLink-Console\Metadata" "L:\Git\View-by-Distance\Metadata" + mklink /J "L:\Git\View-by-Distance-MKLink-Console\Not-Copy-Copy" "L:\Git\View-by-Distance\Not-Copy-Copy" + mklink /J "L:\Git\View-by-Distance-MKLink-Console\PrepareForOld" "L:\Git\View-by-Distance\PrepareForOld" + mklink /J "L:\Git\View-by-Distance-MKLink-Console\Property" "L:\Git\View-by-Distance\Property" + mklink /J "L:\Git\View-by-Distance-MKLink-Console\Property-Compare" "L:\Git\View-by-Distance\Property-Compare" + mklink /J "L:\Git\View-by-Distance-MKLink-Console\Resize" "L:\Git\View-by-Distance\Resize" + mklink /J "L:\Git\View-by-Distance-MKLink-Console\Shared" "L:\Git\View-by-Distance\Shared" diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..c25c58c --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,28 @@ +{ + "version": "0.2.0", + "configurations": [ + { + // Use IntelliSense to find out which attributes exist for C# debugging + // Use hover for the description of the existing attributes + // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md + "name": ".NET Core Launch (console)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + // If you have changed target frameworks, make sure to update the program path. + "programC": "${workspaceFolder}/Compare/bin/Debug/net6.0/win-x64/Compare.dll", + "program": "${workspaceFolder}/Date-Group/bin/Debug/net6.0/win-x64/Date-Group.dll", + "programI": "${workspaceFolder}/Instance/bin/Debug/net6.0/win-x64/Instance.dll", + "programN": "${workspaceFolder}/Not-Copy-Copy/bin/Debug/net6.0/win-x64/Not-Copy-Copy.dll", + "programP": "${workspaceFolder}/PrepareForOld/bin/Debug/net6.0/win-x64/PrepareForOld.dll", + "args": [], + "env": { + "ASPNETCORE_ENVIRONMENT": "Development", + }, + "cwd": "${workspaceFolder}", + // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console + "console": "externalTerminal", + "stopAtEntry": false + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..09ac856 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "cSpell.words": [ + "Barrick", + "Beichler", + "Bohdi", + "Dlib", + "Phares", + "Serilog", + "Vericruz" + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..f9df1ea --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,17 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/Console.sln", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/Compare/.vscode/format-report.json b/Compare/.vscode/format-report.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/Compare/.vscode/format-report.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/Compare/.vscode/launch.json b/Compare/.vscode/launch.json new file mode 100644 index 0000000..e9e82d7 --- /dev/null +++ b/Compare/.vscode/launch.json @@ -0,0 +1,32 @@ +{ + "version": "0.2.0", + "configurations": [ + { + // Use IntelliSense to find out which attributes exist for C# debugging + // Use hover for the description of the existing attributes + // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md + "name": ".NET Core Launch (console)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + // If you have changed target frameworks, make sure to update the program path. + "program": "${workspaceFolder}/bin/Debug/net6.0/win-x64/Compare.dll", + "args": [ + "s" + ], + "env": { + "ASPNETCORE_ENVIRONMENT": "Development", + }, + "cwd": "${workspaceFolder}", + // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console + "console": "externalTerminal", + "stopAtEntry": false + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach", + "processName": "Compare" + } + ] +} \ No newline at end of file diff --git a/Compare/.vscode/settings.json b/Compare/.vscode/settings.json new file mode 100644 index 0000000..768342e --- /dev/null +++ b/Compare/.vscode/settings.json @@ -0,0 +1,14 @@ +{ + "cSpell.words": [ + "Barrick", + "bcdfghjklmnpqrstvwxyz", + "Beichler", + "Bohdi", + "Dlib", + "exif", + "nosj", + "Phares", + "Serilog", + "Vericruz" + ] +} \ No newline at end of file diff --git a/Compare/.vscode/tasks.json b/Compare/.vscode/tasks.json new file mode 100644 index 0000000..31e446d --- /dev/null +++ b/Compare/.vscode/tasks.json @@ -0,0 +1,42 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/Compare.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "publish", + "command": "dotnet", + "type": "process", + "args": [ + "publish", + "${workspaceFolder}/Compare.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "watch", + "command": "dotnet", + "type": "process", + "args": [ + "watch", + "run", + "${workspaceFolder}/Compare.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/Compare/Compare.cs b/Compare/Compare.cs new file mode 100644 index 0000000..1065438 --- /dev/null +++ b/Compare/Compare.cs @@ -0,0 +1,906 @@ +using Microsoft.Extensions.Configuration; +using Phares.Shared; +using System.Globalization; +using System.Text.Json; +using View_by_Distance.Compare.Models; +using View_by_Distance.Property.Models; +using View_by_Distance.Shared.Models.Methods; +using WindowsShortcutFactory; + +namespace View_by_Distance.Compare; + +public class Compare +{ + + private readonly Serilog.ILogger? _Log; + private readonly AppSettings _AppSettings; + private readonly List _Exceptions; + private readonly string[] _VerifyToSeason; + private readonly IsEnvironment _IsEnvironment; + private readonly Models.Configuration _Configuration; + private readonly List> _FileKeyValuePairs; + private readonly List<(string Find, string Replace)> _RenameFindReplace; + private readonly List<(string Find, string Replace)> _RenameBFindReplace; + private readonly List<(string Find, string Replace)> _RenameCFindReplace; + private readonly List<(string Find, string Replace)> _SpellingFindReplace; + private readonly Dictionary>> _FilePropertiesKeyValuePairs; + + public Compare(List args, IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, AppSettings appSettings, string workingDirectory, bool isSilent, IConsole console) + { + if (isSilent) + { } + if (console is null) + { } + string renameFrom; + string renameTo; + string[] segments; + _AppSettings = appSettings; + if (appSettings.MaxDegreeOfParallelism is null) + throw new Exception($"{nameof(appSettings.MaxDegreeOfParallelism)} is null!"); + _RenameFindReplace = new(); + _RenameBFindReplace = new(); + _RenameCFindReplace = new(); + _SpellingFindReplace = new(); + _IsEnvironment = isEnvironment; + _Exceptions = new List(); + _Log = Serilog.Log.ForContext(); + _FileKeyValuePairs = new List>(); + _FilePropertiesKeyValuePairs = new Dictionary>>(); + string message; + string searchPattern = "*"; + long ticks = DateTime.Now.Ticks; + List topDirectories = new(); + Property.Models.Configuration propertyConfiguration = Property.Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory); + Property.Models.Configuration.Verify(propertyConfiguration); + Models.Configuration configuration = Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory, propertyConfiguration); + Verify(configuration); + if (propertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass is null) + throw new Exception($"{nameof(propertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass)} is null!"); + if (propertyConfiguration.PopulatePropertyId is null) + throw new Exception($"{nameof(propertyConfiguration.PopulatePropertyId)} is null!"); + foreach (string spelling in configuration.Spelling) + { + segments = spelling.Split('|'); + if (segments.Length != 2) + throw new Exception("Change configuration"); + if (segments[1].Contains(segments[0])) + throw new Exception($"Change configuration {segments[1]}.Contains({segments[0]})!"); + _SpellingFindReplace.Add(new(segments[0], segments[1])); + } + foreach (string rename in configuration.Rename) + { + segments = rename.Split('|'); + if (segments.Length is not 2 and not 4) + throw new Exception("Change configuration"); + renameFrom = Path.Combine(propertyConfiguration.RootDirectory, segments[0]); + renameTo = Path.Combine(propertyConfiguration.RootDirectory, segments[1]); + if (renameTo.Contains(renameFrom)) + throw new Exception($"Change configuration {renameTo}.Contains({renameFrom})!"); + _RenameFindReplace.Add(new(renameFrom, renameTo)); + if (segments.Length == 4) + { + renameFrom = Path.Combine(propertyConfiguration.RootDirectory, segments[2]); + renameTo = Path.Combine(propertyConfiguration.RootDirectory, segments[3]); + if (renameTo.Contains(renameFrom)) + throw new Exception($"Change configuration {renameTo}.Contains({renameFrom})!"); + _RenameFindReplace.Add(new(renameFrom, renameTo)); + } + } + foreach (string rename in configuration.RenameB) + { + segments = rename.Split('|'); + if (segments.Length is not 2) + throw new Exception("Change configuration"); + renameFrom = Path.GetFullPath(string.Concat(propertyConfiguration.RootDirectory, segments[0])); + renameTo = Path.GetFullPath(string.Concat(propertyConfiguration.RootDirectory, segments[1])); + if (renameTo.Contains(renameFrom)) + throw new Exception($"Change configuration {renameTo}.Contains({renameFrom})!"); + _RenameBFindReplace.Add(new(renameFrom, renameTo)); + } + for (int i = 0; i < configuration.RenameC.Length; i++) + { + renameFrom = Path.GetFullPath(string.Concat(propertyConfiguration.RootDirectory, configuration.RenameC[i])); + renameTo = Path.Combine(propertyConfiguration.RootDirectory, GetRename(configuration.RenameC[i])); + if (renameTo.Contains(renameFrom)) + throw new Exception("Change configuration!"); + _RenameCFindReplace.Add(new(renameFrom, renameTo)); + } + List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> groupCollection = Property.Models.Stateless.A_Property.GetGroupCollection(propertyConfiguration.RootDirectory, searchPattern, topDirectories, propertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass.Value, reverse: false); + if (appSettings.MaxDegreeOfParallelism.Value < 2) + ticks = LogDelta(ticks, nameof(Property.Models.Stateless.A_Property.GetGroupCollection)); + _Log.Information($"{nameof(Property.Models.Stateless.A_Property.GetGroupCollection)} has finished"); + _VerifyToSeason = propertyConfiguration.VerifyToSeason.Select(l => Path.Combine(propertyConfiguration.RootDirectory, l)).ToArray(); + List missingVerifyToSeasonCollection = GetMissingVerifyToSeasonCollection(topDirectories, groupCollection); + if (missingVerifyToSeasonCollection.Any()) + throw new Exception($"Update configuration with the following {Environment.NewLine} {string.Join(Environment.NewLine, missingVerifyToSeasonCollection)}"); + if (PossiblyRename(topDirectories, groupCollection)) + { + topDirectories.Clear(); + _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(propertyConfiguration.RootDirectory); + groupCollection = Property.Models.Stateless.A_Property.GetGroupCollection(propertyConfiguration.RootDirectory, searchPattern, topDirectories, propertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass.Value, reverse: false); + if (appSettings.MaxDegreeOfParallelism.Value < 2) + ticks = LogDelta(ticks, nameof(Property.Models.Stateless.A_Property.GetGroupCollection)); + } + _Log.Information($"{nameof(PossiblyRename)} has finished"); + if (PossiblyRenameB(topDirectories, groupCollection)) + { + topDirectories.Clear(); + _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(propertyConfiguration.RootDirectory); + groupCollection = Property.Models.Stateless.A_Property.GetGroupCollection(propertyConfiguration.RootDirectory, searchPattern, topDirectories, propertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass.Value, reverse: false); + if (appSettings.MaxDegreeOfParallelism.Value < 2) + ticks = LogDelta(ticks, nameof(Property.Models.Stateless.A_Property.GetGroupCollection)); + } + _Log.Information($"{nameof(PossiblyRenameB)} has finished"); + if (PossiblyRenameC(topDirectories, groupCollection)) + { + topDirectories.Clear(); + _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(propertyConfiguration.RootDirectory); + groupCollection = Property.Models.Stateless.A_Property.GetGroupCollection(propertyConfiguration.RootDirectory, searchPattern, topDirectories, propertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass.Value, reverse: false); + if (appSettings.MaxDegreeOfParallelism.Value < 2) + ticks = LogDelta(ticks, nameof(Property.Models.Stateless.A_Property.GetGroupCollection)); + } + _Log.Information($"{nameof(PossiblyRenameC)} has finished"); + if (PossiblyCorrect(topDirectories, groupCollection)) + { + topDirectories.Clear(); + _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(propertyConfiguration.RootDirectory); + groupCollection = Property.Models.Stateless.A_Property.GetGroupCollection(propertyConfiguration.RootDirectory, searchPattern, topDirectories, propertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass.Value, reverse: false); + if (appSettings.MaxDegreeOfParallelism.Value < 2) + ticks = LogDelta(ticks, nameof(Property.Models.Stateless.A_Property.GetGroupCollection)); + } + _Log.Information($"{nameof(PossiblyCorrect)} has finished"); + string[] dbFiles = Directory.GetFiles(propertyConfiguration.RootDirectory, "*.db", SearchOption.AllDirectories); + foreach (string dbFile in dbFiles) + File.Delete(dbFile); + _Log.Information("deleting *.db files has finished"); + if (dbFiles.Any()) + { + topDirectories.Clear(); + _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(propertyConfiguration.RootDirectory); + groupCollection = Property.Models.Stateless.A_Property.GetGroupCollection(propertyConfiguration.RootDirectory, searchPattern, topDirectories, propertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass.Value, reverse: false); + if (appSettings.MaxDegreeOfParallelism.Value < 2) + ticks = LogDelta(ticks, nameof(Property.Models.Stateless.A_Property.GetGroupCollection)); + } + PropertyLogic propertyLogic = GetPropertyLogic(); + if (_IsEnvironment.Development && propertyConfiguration.PopulatePropertyId.Value && !propertyLogic.IndicesFromOld.Any()) + throw new Exception("Copy keyValuePairs-####.json file"); + _Exceptions.AddRange(propertyLogic.DoWork(propertyConfiguration, topDirectories, groupCollection, firstPass: true)); + message = $"There were {_Exceptions.Count} exception(s) thrown! {Environment.NewLine}{string.Join(Environment.NewLine, _Exceptions)}"; + _Log.Information(message); + if (_Exceptions.Count != 0) + throw new Exception(message); + if (appSettings.MaxDegreeOfParallelism.Value < 2) + ticks = LogDelta(ticks, nameof(PropertyLogic.DoWork)); + if (!isSilent) + { + _Log.Information("First pass completed"); + for (int y = 0; y < int.MaxValue; y++) + { + _Log.Information("Press \"Y\" key to continue or close console if compare not needed"); + if (Console.ReadKey().Key == ConsoleKey.Y) + break; + } + _Log.Information(". . ."); + } + string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(propertyConfiguration, nameof(A_Property), "{}"); + string aPropertyContentCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(propertyConfiguration, nameof(A_Property), "[()]"); + if (!isSilent) + { + if (Directory.Exists(aPropertySingletonDirectory)) + { + ConsoleKey? consoleKey = null; + for (int y = 0; y < int.MaxValue; y++) + { + _Log.Information($"Execute {nameof(ChangeExtensionFromDeleteToJson)} \"Y(es)\" or \"N(o)\"?"); + consoleKey = Console.ReadKey().Key; + if (consoleKey is ConsoleKey.Y or ConsoleKey.N) + break; + } + _Log.Information(". . ."); + if (consoleKey == ConsoleKey.Y) + ChangeExtensionFromDeleteToJson(aPropertySingletonDirectory); + for (int y = 0; y < int.MaxValue; y++) + { + _Log.Information($"Execute {nameof(Property.Models.Stateless.A_Property.SearchForAbandonedFilesFull)} \"Y(es)\" or \"N(o)\"?"); + consoleKey = Console.ReadKey().Key; + if (consoleKey is ConsoleKey.Y or ConsoleKey.N) + break; + } + _Log.Information(". . ."); + if (consoleKey == ConsoleKey.Y) + { + Property.Models.Stateless.A_Property.SearchForAbandonedFilesFull(propertyConfiguration.RootDirectory, aPropertySingletonDirectory, onlyJson: false); + for (int y = 0; y < int.MaxValue; y++) + { + _Log.Information($"Execute {nameof(Property.Models.Stateless.IPath.DeleteEmptyDirectories)} \"Y(es)\" or \"N(o)\"?"); + consoleKey = Console.ReadKey().Key; + if (consoleKey is ConsoleKey.Y or ConsoleKey.N) + break; + } + _Log.Information(". . ."); + _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(propertyConfiguration.RootDirectory); + _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(aPropertySingletonDirectory); + } + } + } + topDirectories.Clear(); + groupCollection = Property.Models.Stateless.A_Property.GetGroupCollection(propertyConfiguration.RootDirectory, searchPattern, topDirectories, propertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass.Value, reverse: false); + _Exceptions.AddRange(propertyLogic.DoWork(propertyConfiguration, topDirectories, groupCollection, firstPass: false)); + message = $"There were {_Exceptions.Count} exception(s) thrown! {Environment.NewLine}{string.Join(Environment.NewLine, _Exceptions)}"; + _Log.Information(message); + if (_Exceptions.Count != 0) + throw new Exception(message); + if (!isSilent) + { + _Log.Information("Second pass completed"); + for (int y = 0; y < int.MaxValue; y++) + { + _Log.Information("Press \"Y\" key to continue or close console if compare not needed"); + if (Console.ReadKey().Key == ConsoleKey.Y) + break; + } + _Log.Information(". . ."); + } + ThirdPassToMove(propertyLogic, propertyConfiguration, aPropertyContentCollectionDirectory, topDirectories, groupCollection); + if (!isSilent) + { + _Log.Information("Third pass completed"); + for (int y = 0; y < int.MaxValue; y++) + { + _Log.Information("Press \"Y\" key to continue or close console if compare not needed"); + if (Console.ReadKey().Key == ConsoleKey.Y) + break; + } + _Log.Information(". . ."); + } + FourthPassCreateWindowsShortcuts(propertyLogic, propertyConfiguration, topDirectories, groupCollection, saveToCollection: false, keepAll: false); + if (!isSilent) + { + _Log.Information("Fourth pass completed"); + for (int y = 0; y < int.MaxValue; y++) + { + _Log.Information("Press \"Y\" key to continue or close console if compare not needed"); + if (Console.ReadKey().Key == ConsoleKey.Y) + break; + } + _Log.Information(". . ."); + } + SaveDiffFilesOrSaveLogAndMoveFiles(propertyConfiguration); + string currentYearDirectory = Path.Combine(propertyConfiguration.RootDirectory, $". {DateTime.Now:yyyy}"); + if (!Directory.Exists(currentYearDirectory)) + _ = Directory.CreateDirectory(currentYearDirectory); + _Configuration = configuration; + } + + private string GetRename(string renameA) + { + string result; + int season; + DateTime dateTime; + string seasonName; + string[] pathSegments; + string[] directorySegments; + string corrected = renameA[1..]; + if ((from l in _SpellingFindReplace where corrected.Contains(l.Find) select true).Any()) + { + foreach ((string find, string replace) in _SpellingFindReplace) + corrected = corrected.Replace(find, replace); + } + corrected = corrected.Replace("Back to the hospital", "September 2007").Replace("Birthday", "September 2007").Replace("Aug Sept 09", "Sept 09"); + pathSegments = corrected.Split('/'); + directorySegments = pathSegments[0].Split(' '); + bool hasZzz = directorySegments.Contains("zzz"); + if (hasZzz) + { + corrected = corrected.Replace("zzz ", string.Empty); + pathSegments = corrected.Split('/'); + directorySegments = pathSegments[0].Split(' '); + } + if (pathSegments[^1].Contains('-')) + { + directorySegments = pathSegments[^1].Split(' '); + if (!DateTime.TryParseExact(string.Join(' ', directorySegments.Take(3)), "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) + throw new Exception("l"); + (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); + result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); + } + else if (pathSegments.Length == 1) + { + directorySegments = pathSegments[^1].Split(' '); + if (DateTime.TryParseExact(directorySegments[^1], "yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) + { + (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); + result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); + } + else + throw new Exception("1"); + } + else if (pathSegments.Length == 2) + { + directorySegments = pathSegments[^1].Split(' '); + if (directorySegments.Length == 1) + { + directorySegments = pathSegments[0].Split(' '); + if (DateTime.TryParseExact(directorySegments[^1], "yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) + { + (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); + result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); + } + else + throw new Exception("2,1"); + } + else if (directorySegments.Length == 4) + { + directorySegments = pathSegments[0].Split(' '); + if (DateTime.TryParseExact(directorySegments[^1], "yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) + { + (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); + result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); + } + else + throw new Exception("2,4"); + } + else if (directorySegments.Length == 2) + { + if (DateTime.TryParseExact(string.Join(' ', directorySegments.Take(2)), "MMM yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) + { + (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); + result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); + } + else if (DateTime.TryParseExact(string.Join(' ', directorySegments.Take(2)), "MMM yy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) + { + (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); + result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); + } + else if (DateTime.TryParseExact(string.Concat(directorySegments[0][..3], ' ', directorySegments[1]), "MMM yy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) + { + (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); + result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); + } + else if (DateTime.TryParseExact(string.Join(' ', directorySegments.Take(2)), "MMMM yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) + { + (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); + result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); + } + else + throw new Exception("2,2"); + } + else if (directorySegments.Length == 3) + { + if (DateTime.TryParseExact(string.Join(' ', directorySegments.Take(3)), "MMMM dd yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) + { + (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); + result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); + } + else if (DateTime.TryParseExact(string.Join(' ', directorySegments.Take(3)), "MMMM d yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) + { + (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); + result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); + } + else + throw new Exception("2,3"); + } + else + throw new Exception("2"); + } + else if (pathSegments.Length == 3) + { + directorySegments = pathSegments[^1].Split(' '); + if (DateTime.TryParseExact(string.Join(' ', directorySegments.Take(3)), "MMMM dd yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) + { + (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); + result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); + } + else if (DateTime.TryParseExact(string.Join(' ', directorySegments.Take(3)), "MMMM d yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) + { + (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); + result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); + } + else + throw new Exception("3"); + } + else + throw new Exception("e"); + if (hasZzz) + result = string.Concat("zzz ", result); + return result; + } + + private static void Verify(Models.Configuration configuration) + { + if (configuration.Spelling is null || !configuration.Spelling.Any()) + throw new Exception($"{nameof(configuration.Spelling)} should have at least one!"); + } + + private long LogDelta(long ticks, string methodName) + { + long result; + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + double delta = new TimeSpan(DateTime.Now.Ticks - ticks).TotalMilliseconds; + _Log.Debug($"{methodName} took {Math.Floor(delta)} millisecond(s)"); + result = DateTime.Now.Ticks; + return result; + } + + private PropertyLogic GetPropertyLogic() + { + PropertyLogic result; + if (_AppSettings.MaxDegreeOfParallelism is null) + throw new Exception($"{nameof(_AppSettings.MaxDegreeOfParallelism)} is null!"); + if (_Configuration?.PropertyConfiguration is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + result = new(_AppSettings.MaxDegreeOfParallelism.Value, _Configuration.PropertyConfiguration, _VerifyToSeason); + string fromPerpareForOld = "34720-637858334555170379.tsv"; + string fromPerpareForOldFile = Path.Combine(_Configuration.PropertyConfiguration.RootDirectory, fromPerpareForOld); + if (File.Exists(fromPerpareForOldFile)) + { + string[] lines; + string[] columns; + List debug = new(); + long ticks = DateTime.Now.Ticks; + lines = File.ReadAllLines(fromPerpareForOldFile); + string resultsDirectory = $"{_Configuration.PropertyConfiguration.RootDirectory} - Results"; + int[]? zeros = (from l in result.IndicesFromNew where l.Value.Any() select l.Value[0]).ToArray(); + lines = (from l in result.IndicesFromNew select string.Concat(l.Key, '\t', string.Join('\t', l.Value))).ToArray(); + if (!Directory.Exists(resultsDirectory)) + _ = Directory.CreateDirectory(resultsDirectory); + File.WriteAllLines(Path.Combine(resultsDirectory, $"{ticks}.tsv"), lines); + string json = JsonSerializer.Serialize(result.IndicesFromNew, new JsonSerializerOptions { WriteIndented = true }); + File.WriteAllText(Path.Combine(resultsDirectory, $"{ticks}.json"), json); + foreach (string line in lines) + { + columns = line.Split('\t'); + // select $"{l.Index}\t{l.PropertyId}\t{l.RegexResult}\t{new DateTime(l.Ticks):yyyy-MM-dd_HH-mm-ss}\t{l.PropertyTicks}\t{l.RelativeDirectory}\t{l.FileName}" + if (columns.Length != 7) + continue; + if (!int.TryParse(columns[1], out int propertyId)) + continue; + if (!zeros.Contains(propertyId)) + debug.Add(line); + else + debug.Add(propertyId.ToString()); + } + File.WriteAllLines(Path.Combine(resultsDirectory, $"{ticks}-{fromPerpareForOld}"), debug); + } + return result; + } + + private void SaveDiffFilesOrSaveLogAndMoveFiles(Property.Models.Configuration configuration) + { + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + if (_AppSettings.MaxDegreeOfParallelism is null) + throw new Exception($"{nameof(_AppSettings.MaxDegreeOfParallelism)} is null!"); + if (_Configuration?.PropertyConfiguration is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "{}"); + _Log.Information(aPropertySingletonDirectory); + _Log.Information("to"); + _Log.Information(_Configuration.DiffPropertyDirectory); + for (int y = 0; y < int.MaxValue; y++) + { + _Log.Information("Press \"Y\" key to continue or close console if compare not needed"); + if (Console.ReadKey().Key == ConsoleKey.Y) + break; + } + _Log.Information(". . ."); + int loadLessThan = 7; + string diffRootDirectory; + ConsoleKey? consoleKey = null; + List? duplicates = null; + PropertyCompare.Models.PropertyCompare[] diffPropertyCompareCollection; + if (string.IsNullOrEmpty(_Configuration.DiffPropertyDirectory)) + diffRootDirectory = string.Empty; + else + { + if (!_Configuration.DiffPropertyDirectory.EndsWith("{}")) + throw new Exception("Invalid directory should end with {}!"); + diffRootDirectory = Property.Models.Stateless.A_Property.GetDiffRootDirectory(_Configuration.DiffPropertyDirectory); + } + PropertyCompare.Models.PropertyCompareLogic propertyCompareLogic = new(_AppSettings.MaxDegreeOfParallelism.Value, _Configuration.PropertyConfiguration, _SpellingFindReplace, diffRootDirectory); + if (string.IsNullOrEmpty(_Configuration.DiffPropertyDirectory) || !Directory.Exists(_Configuration.DiffPropertyDirectory)) + diffPropertyCompareCollection = Array.Empty(); + else + { + diffPropertyCompareCollection = propertyCompareLogic.Get(_Configuration.DiffPropertyDirectory, loadLessThan, duplicates, deleteExtension: false); + if (!diffPropertyCompareCollection.Any()) + throw new Exception("Invalid directory!"); + } + string aPropertyCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "[{}]"); + PropertyCompare.Models.PropertyCompare[] propertyCompareCollection = propertyCompareLogic.Get(aPropertySingletonDirectory, loadLessThan, duplicates, deleteExtension: false); + { + long ticks = DateTime.Now.Ticks; + string[] lines = (from l in propertyCompareCollection select l.GetSelect()).ToArray(); + File.WriteAllLines(Path.Join(aPropertyCollectionDirectory, $". . . Ids - {ticks}.txt"), lines); + string json = JsonSerializer.Serialize(propertyCompareCollection, new JsonSerializerOptions { WriteIndented = true }); + File.WriteAllText(Path.Join(aPropertyCollectionDirectory, $". . . Ids - {ticks}.nosj"), json); + } + for (int x = 0; x < int.MaxValue; x++) + { + _Log.Information($"Press \"D\" key to {nameof(PropertyCompare.Models.PropertyCompareLogic.SaveDiffFiles)}"); + _Log.Information($"Press \"M\" key to {nameof(PropertyCompare.Models.PropertyCompareLogic.SaveLogAndMoveFiles)}"); + _Log.Information("Press \"End\" key when ready to skip"); + consoleKey = Console.ReadKey().Key; + if (consoleKey is ConsoleKey.D or ConsoleKey.M or ConsoleKey.End) + break; + } + _Log.Information(". . ."); + if (consoleKey.HasValue && consoleKey.Value == ConsoleKey.D) + propertyCompareLogic.SaveDiffFiles(aPropertyCollectionDirectory, loadLessThan, propertyCompareCollection, diffPropertyCompareCollection); + else if (consoleKey.HasValue && consoleKey.Value == ConsoleKey.M) + { + for (int x = 0; x < int.MaxValue; x++) + { + _Log.Information($"Press \"0 - {loadLessThan}\" key when ready to continue"); + _Log.Information("Press \"End\" key when ready to skip"); + consoleKey = Console.ReadKey().Key; + if (consoleKey.Value is ConsoleKey.D0 or ConsoleKey.D1 or ConsoleKey.D2 or ConsoleKey.D3 or ConsoleKey.D4 or ConsoleKey.D5 or ConsoleKey.D6 or ConsoleKey.End) + break; + } + _Log.Information(". . ."); + int i = int.Parse(consoleKey.Value.ToString()[1..]); + propertyCompareLogic.SaveLogAndMoveFiles(aPropertyCollectionDirectory, loadLessThan, propertyCompareCollection, diffPropertyCompareCollection, i); + } + } + + private void ChangeExtensionFromDeleteToJson(string aPropertySingletonDirectory) + { + if (_AppSettings.MaxDegreeOfParallelism is null) + throw new Exception($"{nameof(_AppSettings.MaxDegreeOfParallelism)} is null!"); + string searchPattern = "*.delete"; + long ticks = DateTime.Now.Ticks; + List topDirectories = new(); + List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> groupCollection = Property.Models.Stateless.A_Property.GetGroupCollection(aPropertySingletonDirectory, searchPattern, topDirectories); + if (_AppSettings.MaxDegreeOfParallelism.Value < 2) + ticks = LogDelta(ticks, nameof(Property.Models.Stateless.A_Property.GetGroupCollection)); + foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles, int r) in groupCollection) + { + if (!topDirectories.Any()) + continue; + foreach (string sourceDirectoryFile in sourceDirectoryFiles) + File.Move(sourceDirectoryFile, Path.ChangeExtension(sourceDirectoryFile, ".json")); + } + } + + private bool PossiblyRename(List topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> groupCollection) + { + bool result = false; + string replaceFile; + string replaceDirectory; + int remainingDirectories = 0; + IEnumerable<(string Find, string Replace)>? found; + foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles, int r) in groupCollection) + { + if (!topDirectories.Any()) + continue; + found = from l in _RenameFindReplace where sourceDirectory == l.Find select l; + if (!found.Any()) + continue; + if (!result) + result = true; + replaceDirectory = found.First().Replace; + if (!Directory.Exists(replaceDirectory)) + Directory.Move(sourceDirectory, replaceDirectory); + else + { + if (Directory.EnumerateDirectories(sourceDirectory).Any()) + remainingDirectories += 1; + else + { + foreach (string sourceDirectoryFile in sourceDirectoryFiles) + { + replaceFile = Path.Combine(replaceDirectory, Path.GetFileName(sourceDirectoryFile)); + if (File.Exists(replaceFile)) + { + if (replaceFile.EndsWith(".jpg", ignoreCase: true, CultureInfo.CurrentCulture)) + replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpeg")); + else if (replaceFile.EndsWith(".jpeg", ignoreCase: true, CultureInfo.CurrentCulture)) + replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpg")); + } + if (File.Exists(replaceFile)) + continue; + File.Move(sourceDirectoryFile, replaceFile); + } + } + } + } + return result; + } + + private bool PossiblyRenameB(List topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> groupCollection) + { + bool result = false; + string replaceFile; + string replaceDirectory; + IEnumerable<(string Find, string Replace)>? found; + foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles, int r) in groupCollection) + { + if (!topDirectories.Any()) + continue; + found = from l in _RenameBFindReplace where sourceDirectory == l.Find select l; + if (!found.Any()) + continue; + if (!result) + result = true; + replaceDirectory = found.First().Replace; + if (!Directory.Exists(replaceDirectory)) + _ = Directory.CreateDirectory(replaceDirectory); + foreach (string sourceDirectoryFile in sourceDirectoryFiles) + { + replaceFile = Path.Combine(replaceDirectory, Path.GetFileName(sourceDirectoryFile)); + if (File.Exists(replaceFile)) + { + if (replaceFile.EndsWith(".jpg", ignoreCase: true, CultureInfo.CurrentCulture)) + replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpeg")); + else if (replaceFile.EndsWith(".jpeg", ignoreCase: true, CultureInfo.CurrentCulture)) + replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpg")); + } + if (File.Exists(replaceFile)) + continue; + File.Move(sourceDirectoryFile, replaceFile); + } + } + return result; + } + + private bool PossiblyRenameC(List topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> groupCollection) + { + bool result = false; + string replaceFile; + string replaceDirectory; + IEnumerable<(string Find, string Replace)>? found; + foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles, int r) in groupCollection) + { + if (!topDirectories.Any()) + continue; + found = from l in _RenameCFindReplace where sourceDirectory == l.Find select l; + if (!found.Any()) + continue; + if (!result) + result = true; + replaceDirectory = found.First().Replace; + if (!Directory.Exists(replaceDirectory)) + _ = Directory.CreateDirectory(replaceDirectory); + foreach (string sourceDirectoryFile in sourceDirectoryFiles) + { + replaceFile = Path.Combine(replaceDirectory, Path.GetFileName(sourceDirectoryFile)); + if (File.Exists(replaceFile)) + { + if (replaceFile.EndsWith(".jpg", ignoreCase: true, CultureInfo.CurrentCulture)) + replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpeg")); + else if (replaceFile.EndsWith(".jpeg", ignoreCase: true, CultureInfo.CurrentCulture)) + replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpg")); + } + if (File.Exists(replaceFile)) + continue; + File.Move(sourceDirectoryFile, replaceFile); + } + } + return result; + } + + private bool PossiblyCorrect(List topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> groupCollection) + { + if (_Configuration?.PropertyConfiguration is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + bool result = false; + string corrected; + string correctedMoveTo; + string? correctedDirectory; + string filteredSourceDirectoryFile; + string[] filteredSourceDirectoryFiles; + (string Find, string Replace) findReplace; + IEnumerable<(string Find, string Replace)>? found; + foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles, int r) in groupCollection) + { + if (!topDirectories.Any()) + continue; + filteredSourceDirectoryFiles = (from l in sourceDirectoryFiles where !_Configuration.PropertyConfiguration.IgnoreExtensions.Contains(Path.GetExtension(l)) select l).ToArray(); + if (!filteredSourceDirectoryFiles.Any()) + continue; + for (int i = 0; i < filteredSourceDirectoryFiles.Length; i++) + { + found = null; + for (int z = 0; z < int.MaxValue; z++) + { + filteredSourceDirectoryFile = filteredSourceDirectoryFiles[i]; + found = from l in _SpellingFindReplace where filteredSourceDirectoryFile.Contains(l.Find) select l; + if (!found.Any()) + break; + findReplace = found.First(); + corrected = filteredSourceDirectoryFile.Replace(findReplace.Find, findReplace.Replace); + correctedDirectory = Path.GetDirectoryName(corrected); + if (string.IsNullOrEmpty(correctedDirectory)) + break; + correctedMoveTo = Path.Combine(correctedDirectory, Path.GetFileName(corrected)); + if (File.Exists(correctedMoveTo)) + break; + if (!Directory.Exists(correctedDirectory)) + _ = Directory.CreateDirectory(correctedDirectory); + if (!result) + result = true; + File.Move(filteredSourceDirectoryFile, correctedMoveTo); + filteredSourceDirectoryFiles[i] = corrected; + } + } + } + return result; + } + + private List GetMissingVerifyToSeasonCollection(List _, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> groupCollection) + { + if (_Configuration?.PropertyConfiguration is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + List results = new(); + string check; + foreach ((int _, string sourceDirectory, string[] _, int _) in groupCollection) + { + if (sourceDirectory == _Configuration.PropertyConfiguration.RootDirectory) + continue; + check = sourceDirectory[(_Configuration.PropertyConfiguration.RootDirectory.Length + 1)..]; + if (check[0] is '=' || check.StartsWith("zzz =")) + { + if (!_Configuration.PropertyConfiguration.VerifyToSeason.Contains(check)) + results.Add(check); + } + } + return results; + } + + private void CreateWindowsShortcuts((long Ticks, string FilteredSourceDirectoryFile, string PropertyDirectory, int PropertyId)[] collection, bool keepAll) + { + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + int z = 0; + string fileName; + WindowsShortcut windowsShortcut; + foreach ((long ticks, string filteredSourceDirectoryFile, string propertyDirectory, int propertyId) in collection) + { + z += 1; + if (z % 1000 == 0) + _Log.Debug($"{z}) Loop {propertyDirectory}"); + if (!keepAll) + { + fileName = Path.Combine(propertyDirectory, $"{propertyId}.lnk"); + if (File.Exists(fileName)) + continue; + } + else + { + fileName = string.Empty; + for (short c = 65; c < short.MaxValue; c++) + { + if (c > 95) + break; + fileName = Path.Combine(propertyDirectory, $"{(char)c}", $"{propertyId}.lnk"); + if (File.Exists(fileName)) + continue; + } + } + if (string.IsNullOrEmpty(fileName)) + continue; + windowsShortcut = new() { Path = filteredSourceDirectoryFile }; + windowsShortcut.Save(fileName); + windowsShortcut.Dispose(); + } + } + + private void ThirdPassToMove(PropertyLogic propertyLogic, Property.Models.Configuration configuration, string aPropertyContentCollectionDirectory, List topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> groupCollection) + { + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + if (_Configuration?.PropertyConfiguration is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + int stay = 0; + string fileName; + string id = " - Id"; + A_Property? property; + string? directoryName; + ConsoleKey? consoleKey = null; + DateTime dateTime = DateTime.Now; + string filteredSourceDirectoryFile; + List fileStayCollection = new(); + List fileMoveCollection = new(); + List distinctDirectories = new(); + List> valueCollection = new(); + List groupResultsCollection = propertyLogic.GetParallelWork(configuration, topDirectories, groupCollection, firstPass: false, filterOnFirstPass: false); + foreach (Group group in groupResultsCollection) + { + for (int i = 0; i < group.PropertyCollection.Length; i++) + { + property = group.PropertyCollection[i]; + if (property?.Id is null) + continue; + filteredSourceDirectoryFile = group.FilteredSourceDirectoryFiles[i]; + valueCollection.Add(new(property.Id.Value, property.Indices)); + if (!propertyLogic.IndicesFromNew.ContainsKey(property.Id.Value)) + stay += 1; + else if (!fileMoveCollection.Contains(filteredSourceDirectoryFile)) + fileMoveCollection.Add(filteredSourceDirectoryFile); + } + } + string[] lines = (from l in valueCollection select string.Concat(l.Key, '\t', string.Join('\t', l.Value))).ToArray(); + if (!Directory.Exists(aPropertyContentCollectionDirectory)) + _ = Directory.CreateDirectory(aPropertyContentCollectionDirectory); + File.WriteAllLines(Path.Combine(aPropertyContentCollectionDirectory, $"{dateTime.Ticks}.tsv"), lines); + string json = JsonSerializer.Serialize(valueCollection, new JsonSerializerOptions { WriteIndented = true }); + File.WriteAllText(Path.Combine(aPropertyContentCollectionDirectory, $"{dateTime.Ticks}.json"), json); + foreach (string fileMove in fileMoveCollection) + { + directoryName = Path.GetDirectoryName(string.Concat(_Configuration.PropertyConfiguration.RootDirectory, id, fileMove[_Configuration.PropertyConfiguration.RootDirectory.Length..])); + if (string.IsNullOrEmpty(directoryName)) + continue; + if (!distinctDirectories.Contains(directoryName)) + distinctDirectories.Add(directoryName); + } + foreach (string distinctDirectory in distinctDirectories) + { + if (!Directory.Exists(distinctDirectory)) + _ = Directory.CreateDirectory(distinctDirectory); + } + _Log.Information($"{stay} file(s) are staying and {fileMoveCollection.Count} file(s) will be moved"); + for (int y = 0; y < int.MaxValue; y++) + { + _Log.Information($"Press \"M\" key to {nameof(File.Move)}"); + _Log.Information("Press \"End\" key when ready to skip or close console if compare not needed"); + consoleKey = Console.ReadKey().Key; + if (consoleKey is ConsoleKey.M or ConsoleKey.End) + break; + } + _Log.Information(". . ."); + if (consoleKey.HasValue && consoleKey.Value == ConsoleKey.M) + { + foreach (string fileMove in fileMoveCollection) + { + fileName = string.Concat(_Configuration.PropertyConfiguration.RootDirectory, id, fileMove[_Configuration.PropertyConfiguration.RootDirectory.Length..]); + File.Move(fileMove, fileName); + } + for (int i = 1; i < 4; i++) + _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(_Configuration.PropertyConfiguration.RootDirectory); + } + } + + private void FourthPassCreateWindowsShortcuts(PropertyLogic propertyLogic, Property.Models.Configuration configuration, List topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> groupCollection, bool saveToCollection, bool keepAll) + { + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + int stay = 0; + A_Property? property; + ConsoleKey? consoleKey = null; + string filteredSourceDirectoryFile; + List fileMoveCollection = new(); + List> valueCollection = new(); + (long Ticks, string FilteredSourceDirectoryFile, string PropertyDirectory, int PropertyId)[] collection; + List groupResultsCollection = propertyLogic.GetParallelWork(configuration, topDirectories, groupCollection, firstPass: false, filterOnFirstPass: false); + foreach (Group group in groupResultsCollection) + { + for (int i = 0; i < group.PropertyCollection.Length; i++) + { + property = group.PropertyCollection[i]; + if (property?.Id is null) + continue; + filteredSourceDirectoryFile = group.FilteredSourceDirectoryFiles[i]; + valueCollection.Add(new(property.Id.Value, property.Indices)); + if (!propertyLogic.IndicesFromNew.ContainsKey(property.Id.Value)) + stay += 1; + else + fileMoveCollection.Add(filteredSourceDirectoryFile); + } + } + collection = propertyLogic.GetPropertyIds(configuration, groupResultsCollection, saveToCollection); + _Log.Information($"{stay} file(s) are staying and {fileMoveCollection.Count} file(s) will be moved"); + for (int x = 0; x < int.MaxValue; x++) + { + _Log.Information($"Press \"S\" key to {nameof(CreateWindowsShortcuts)}"); + _Log.Information("Press \"End\" key when ready to skip or close console if compare not needed"); + consoleKey = Console.ReadKey().Key; + if (consoleKey is ConsoleKey.M or ConsoleKey.End) + break; + } + _Log.Information(". . ."); + if (consoleKey.HasValue && consoleKey.Value == ConsoleKey.S) + CreateWindowsShortcuts(collection, keepAll); + } + +} \ No newline at end of file diff --git a/Compare/Compare.csproj b/Compare/Compare.csproj new file mode 100644 index 0000000..5701469 --- /dev/null +++ b/Compare/Compare.csproj @@ -0,0 +1,67 @@ + + + enable + 10.0 + enable + Exe + win-x64 + net6.0 + + + Phares.View.by.Distance.Compare + false + 5.0.402.104 + Mike Phares + Phares + true + snupkg + + + true + true + true + + + Windows + + + OSX + + + Linux + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Always + + + Always + + + \ No newline at end of file diff --git a/Compare/Models/AppSettings.cs b/Compare/Models/AppSettings.cs new file mode 100644 index 0000000..6c0b44d --- /dev/null +++ b/Compare/Models/AppSettings.cs @@ -0,0 +1,35 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Compare.Models; + +public class AppSettings +{ + + protected string _Company; + protected string _WorkingDirectoryName; + protected int? _MaxDegreeOfParallelism; + public string Company => _Company; + public string WorkingDirectoryName => _WorkingDirectoryName; + public int? MaxDegreeOfParallelism => _MaxDegreeOfParallelism; + + // public AppSettings() + // { + + // } + + [JsonConstructor] + public AppSettings(string company, string workingDirectoryName, int? maxDegreeOfParallelism) + { + _Company = company; + _WorkingDirectoryName = workingDirectoryName; + _MaxDegreeOfParallelism = maxDegreeOfParallelism; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/Compare/Models/Binder/AppSettings.cs b/Compare/Models/Binder/AppSettings.cs new file mode 100644 index 0000000..d9c160d --- /dev/null +++ b/Compare/Models/Binder/AppSettings.cs @@ -0,0 +1,26 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.Json; + +namespace View_by_Distance.Compare.Models.Binder; + +public class AppSettings +{ + + [Display(Name = "Company"), Required] public string Company { get; set; } + [Display(Name = "Working Directory Name"), Required] public string WorkingDirectoryName { get; set; } + [Display(Name = "Max Degree Of Parallelism"), Required] public int? MaxDegreeOfParallelism { get; set; } + + public AppSettings() + { + Company = string.Empty; + WorkingDirectoryName = string.Empty; + MaxDegreeOfParallelism = -1; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/Compare/Models/Binder/Configuration.cs b/Compare/Models/Binder/Configuration.cs new file mode 100644 index 0000000..bab0010 --- /dev/null +++ b/Compare/Models/Binder/Configuration.cs @@ -0,0 +1,30 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.Json; + +namespace View_by_Distance.Compare.Models.Binder; + +public class Configuration +{ + [Display(Name = "Diff Property Directory"), Required] public string DiffPropertyDirectory { get; set; } + [Display(Name = "Property Configuration"), Required] public Property.Models.Configuration? PropertyConfiguration { get; set; } + [Display(Name = "Rename"), Required] public string[] Rename { get; set; } + [Display(Name = "Rename B"), Required] public string[] RenameB { get; set; } + [Display(Name = "Rename C"), Required] public string[] RenameC { get; set; } + [Display(Name = "Spelling"), Required] public string[] Spelling { get; set; } + + public Configuration() + { + DiffPropertyDirectory = string.Empty; + Rename = Array.Empty(); + RenameB = Array.Empty(); + RenameC = Array.Empty(); + Spelling = Array.Empty(); + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/Compare/Models/Configuration.cs b/Compare/Models/Configuration.cs new file mode 100644 index 0000000..4f02890 --- /dev/null +++ b/Compare/Models/Configuration.cs @@ -0,0 +1,43 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Compare.Models; + +public class Configuration +{ + + protected readonly string _DiffPropertyDirectory; + protected Property.Models.Configuration? _PropertyConfiguration; + protected readonly string[] _Rename; + protected readonly string[] _RenameB; + protected readonly string[] _RenameC; + protected readonly string[] _Spelling; + public string DiffPropertyDirectory => _DiffPropertyDirectory; + public Property.Models.Configuration? PropertyConfiguration => _PropertyConfiguration; + public string[] Rename => _Rename; + public string[] RenameB => _RenameB; + public string[] RenameC => _RenameC; + public string[] Spelling => _Spelling; + + [JsonConstructor] + public Configuration(string diffPropertyDirectory, Property.Models.Configuration? propertyConfiguration, string[] rename, string[] renameB, string[] renameC, string[] spelling) + { + _DiffPropertyDirectory = diffPropertyDirectory; + _PropertyConfiguration = propertyConfiguration; + _Rename = rename; + _RenameB = renameB; + _RenameC = renameC; + _Spelling = spelling; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + + public void Set(Property.Models.Configuration propertyConfiguration) => _PropertyConfiguration = propertyConfiguration; + + public void Update() => _PropertyConfiguration?.Update(); + +} \ No newline at end of file diff --git a/Compare/Models/Stateless/AppSettings.cs b/Compare/Models/Stateless/AppSettings.cs new file mode 100644 index 0000000..395e813 --- /dev/null +++ b/Compare/Models/Stateless/AppSettings.cs @@ -0,0 +1,40 @@ +using Microsoft.Extensions.Configuration; +using System.Text.Json; + +namespace View_by_Distance.Compare.Models.Stateless; + +public abstract class AppSettings +{ + + public static Models.AppSettings Get(IConfigurationRoot configurationRoot) + { + Models.AppSettings? result; + Binder.AppSettings appSettings = configurationRoot.Get(); + string json = JsonSerializer.Serialize(appSettings, new JsonSerializerOptions() { WriteIndented = true }); + result = JsonSerializer.Deserialize(json); + if (result is null) + throw new Exception(json); + if (string.IsNullOrEmpty(result.Company)) + throw new Exception(json); + string jsonThis = result.ToString(); + if (jsonThis != json) + { + int? check = null; + int min = new int[] { json.Length, jsonThis.Length }.Min(); + for (int i = 0; i < min; i++) + { + if (json[i] == jsonThis[i]) + continue; + check = i; + break; + } + if (check is null) + throw new Exception(); + string a = json[..check.Value].Split(',')[^1]; + string b = json[check.Value..].Split(',')[0]; + throw new Exception($"{a}{b}"); + } + return result; + } + +} \ No newline at end of file diff --git a/Compare/Models/Stateless/Configuration.cs b/Compare/Models/Stateless/Configuration.cs new file mode 100644 index 0000000..4b1425f --- /dev/null +++ b/Compare/Models/Stateless/Configuration.cs @@ -0,0 +1,44 @@ +using Microsoft.Extensions.Configuration; +using Phares.Shared; +using System.Text.Json; + +namespace View_by_Distance.Compare.Models.Stateless; + +public abstract class Configuration +{ + + public static Models.Configuration Get(IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, string workingDirectory, Property.Models.Configuration propertyConfiguration) + { + Models.Configuration? result; + string environmentName = IsEnvironment.GetEnvironmentName(isEnvironment); + string section = string.Concat(environmentName, ":", nameof(Binder.Configuration)); + IConfigurationSection configurationSection = configurationRoot.GetSection(section); + Binder.Configuration configuration = configurationSection.Get(); + string json = JsonSerializer.Serialize(configuration, new JsonSerializerOptions() { WriteIndented = true }); + result = JsonSerializer.Deserialize(json); + if (result is null) + throw new Exception(json); + string jsonThis = result.ToString(); + result.Set(propertyConfiguration); + result.Update(); + if (jsonThis != json) + { + int? check = null; + int min = new int[] { json.Length, jsonThis.Length }.Min(); + for (int i = 0; i < min; i++) + { + if (json[i] == jsonThis[i]) + continue; + check = i; + break; + } + if (check is null) + throw new Exception(); + string a = json[..check.Value].Split(',')[^1]; + string b = json[check.Value..].Split(',')[0]; + throw new Exception($"{a}{b}"); + } + return result; + } + +} \ No newline at end of file diff --git a/Compare/Models/Stateless/SerilogExtensionMethods.cs b/Compare/Models/Stateless/SerilogExtensionMethods.cs new file mode 100644 index 0000000..667f356 --- /dev/null +++ b/Compare/Models/Stateless/SerilogExtensionMethods.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Compare.Models.Stateless; + +public static class SerilogExtensionMethods +{ + + internal static void Warn(this Serilog.ILogger log, string messageTemplate) => log.Warning(messageTemplate); + + internal static void Info(this Serilog.ILogger log, string messageTemplate) => log.Information(messageTemplate); + +} \ No newline at end of file diff --git a/Compare/Program.cs b/Compare/Program.cs new file mode 100644 index 0000000..8618984 --- /dev/null +++ b/Compare/Program.cs @@ -0,0 +1,71 @@ +using Microsoft.Extensions.Configuration; +using Phares.Shared; +using Serilog; +using System.Diagnostics; +using System.Reflection; +using View_by_Distance.Compare.Models; +using View_by_Distance.Shared.Models.Stateless.Methods; + +namespace View_by_Distance.Compare; + +public class Program +{ + + public static void Secondary(List args) + { + LoggerConfiguration loggerConfiguration = new(); + Assembly assembly = Assembly.GetExecutingAssembly(); + bool debuggerWasAttachedAtLineZero = Debugger.IsAttached || assembly.Location.Contains(@"\bin\Debug"); + IsEnvironment isEnvironment = new(processesCount: null, nullASPNetCoreEnvironmentIsDevelopment: debuggerWasAttachedAtLineZero, nullASPNetCoreEnvironmentIsProduction: !debuggerWasAttachedAtLineZero); + IConfigurationBuilder configurationBuilder = new ConfigurationBuilder() + .AddEnvironmentVariables() + .AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true); + IConfigurationRoot configurationRoot = configurationBuilder.Build(); + AppSettings appSettings = Models.Stateless.AppSettings.Get(configurationRoot); + if (appSettings.MaxDegreeOfParallelism is null) + throw new Exception("MaxDegreeOfParallelism must be set!"); + if (appSettings.MaxDegreeOfParallelism.Value > Environment.ProcessorCount) + throw new Exception("MaxDegreeOfParallelism must be =< Environment.ProcessorCount!"); + if (string.IsNullOrEmpty(appSettings.WorkingDirectoryName)) + throw new Exception("Working directory name must have a value!"); + string workingDirectory = IWorkingDirectory.GetWorkingDirectory(assembly.GetName().Name, appSettings.WorkingDirectoryName); + Environment.SetEnvironmentVariable(nameof(workingDirectory), workingDirectory); + _ = ConfigurationLoggerConfigurationExtensions.Configuration(loggerConfiguration.ReadFrom, configurationRoot); + Log.Logger = loggerConfiguration.CreateLogger(); + ILogger log = Log.ForContext(); + int silentIndex = args.IndexOf("s"); + if (silentIndex > -1) + args.RemoveAt(silentIndex); + try + { + if (args is null) + throw new Exception("args is null!"); + Shared.Models.Console console = new(); + Compare _ = new(args, isEnvironment, configurationRoot, appSettings, workingDirectory, silentIndex > -1, console); + } + catch (Exception ex) + { + log.Fatal(string.Concat(ex.Message, Environment.NewLine, ex.StackTrace)); + } + finally + { + Log.CloseAndFlush(); + } + if (silentIndex > -1) + log.Debug("Done. Bye"); + else + { + log.Debug("Done. Press 'Enter' to end"); + _ = Console.ReadLine(); + } + } + + public static void Main(string[] args) + { + if (args is not null) + Secondary(args.ToList()); + else + Secondary(new List()); + } + +} \ No newline at end of file diff --git a/Compare/appsettings.Development.json b/Compare/appsettings.Development.json new file mode 100644 index 0000000..7a0b764 --- /dev/null +++ b/Compare/appsettings.Development.json @@ -0,0 +1,1609 @@ +{ + "Company": "Mike Phares", + "Linux": {}, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Log4netProvider": "Debug", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "MaxDegreeOfParallelism": 6, + "Serilog": { + "Using": [ + "Serilog.Sinks.Console", + "Serilog.Sinks.File" + ], + "MinimumLevel": "Debug", + "WriteTo": [ + { + "Name": "Debug", + "Args": { + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}" + } + }, + { + "Name": "Console", + "Args": { + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "%workingDirectory% - Log/log-.txt", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}", + "rollingInterval": "Hour" + } + } + ], + "Enrich": [ + "FromLogContext", + "WithMachineName", + "WithThreadId" + ], + "Properties": { + "Application": "Sample" + } + }, + "WorkingDirectoryName": "PharesApps", + "Windows": { + "ManualChanges": [ + "I:/Images 2013-12-15 - 27,202 Files, 330 Folders - 26.7 GB", + "I:/Images 2018-05-12 - 32,394 Files, 879 Folders - 53.5 GB", + "I:/Images 2018-12-25 - 33,346 Files, 488 Folders - 58.4 GB", + "I:/Images 2019-06-08 - 34,627 Files, 498 Folders - 64.5 GB", + "I:/Images 2021-10-29 - 40,517 Files, 528 Folders - 79.3 GB", + "I:/Images 2021-10-29 - - GB", + "I:/Images 2019-06-08 - 000035 Files, 006 Folders - 28.8 MB", + "I:/Images 2018-12-25 - 000045 Files, 009 Folders - 56.1 MB", + "I:/Images 2018-05-12 - 09,029 Files, 589 Folders - 15.0 GB", + "I:/Images 2013-12-15 - 13,848 Files, 214 Folders - 12.9 GB", + "/Tracy Picture Partition/2013 July- Dec/September 2013/September 27 2013/DSC_0658.JPG", + "/Greer, AZ 2016/DSC_2182.JPG", + "March 2013", + "May 2011", + "Spring 2018", + "Summer 2011", + "Winter 2018", + "/zzz Patrick", + "Chelsea 2012", + "Chelsea 2013", + "Seattle 2003", + "Seattle 2010", + "Seattle 2011", + "Jason's 11th Birthday 2009|Blackberry (878).jpg|Photo-0245.jpg", + "Blackberry|. 2009|. 2010|. 2011", + "Phone pictures|. 2010|. 2011|. 2012|. 2013", + "/zzz Phares Slides/Slides 2015-06-10/Magazine 01" + ], + "Configuration": { + "DateGroup": "2022-04-07", + "DiffPropertyDirectory": "", + "FileNameDirectorySeparator": ".Z.", + "ForcePropertyLastWriteTimeToCreationTime": false, + "MaxImagesInDirectoryForTopLevelFirstPass": 50, + "Pattern": "[^ABCDEFGHIJKLMNOPQRSTUVWXYZbcdfghjklmnpqrstvwxyz0-9]", + "PopulatePropertyId": true, + "PropertiesChangedForProperty": false, + "RootDirectory": "C:/Tmp/Phares/Compare/Images 2022-04-17 - fa60aa45ebb55fe3ee0ce4da8a64e40611e7d5ce - III", + "WriteBitmapDataBytes": false, + "IgnoreExtensions": [ + ".gif", + ".GIF" + ], + "PropertyContentCollectionFiles": [ + "/Images 2022-04-17 - fa60aa45ebb55fe3ee0ce4da8a64e40611e7d5ce - III - Results/A) Property/2022-04-07/[()]/637869381676042455.json", + "/Not-Copy-Copy/Images 2019-06-08 - 34a9240ac28b52da97428d7725153a80a757ee6b - Not-Copy-Copy - Results/A) Property/2022-04-07/[()]/637869733124119330.json", + "/Not-Copy-Copy/Images 2018-12-25 - 34a9240ac28b52da97428d7725153a80a757ee6b - Not-Copy-Copy - Results/A) Property/2022-04-07/[()]/637869734240700328.json", + "/Not-Copy-Copy/Images 2018-05-12 - b01d4763d8853b6d6057a3870b2723449726da75 - Not-Copy-Copy - Results/A) Property/2022-04-07/[()]/637869734970730630.json", + "/Not-Copy-Copy/Images 2013-12-15 - d02c8791fa0b130c0bce2d39ee684e50f7ee7a97 - Not-Copy-Copy - Results/A) Property/2022-04-07/[()]/637869743752078399.json", + "/Not-Copy-Copy - Delta/Amazon Drive - Results/A) Property/2022-04-07/[()]/637869744751177715.json", + "/Not-Copy-Copy - Delta/Blackberry - Results/A) Property/2022-04-07/[()]/637869745134124462.json" + ], + "ValidImageFormatExtensions": [ + ".bmp", + ".BMP", + ".gif", + ".GIF", + ".jpeg", + ".JPEG", + ".jpg", + ".JPG", + ".png", + ".PNG", + ".tiff", + ".TIFF" + ], + "ValidMetadataExtensions": [ + ".3gp", + ".3GP", + ".amr", + ".AMR", + ".avi", + ".AVI", + ".bmp", + ".BMP", + ".gif", + ".GIF", + ".ico", + ".ICO", + ".jpeg", + ".JPEG", + ".jpg", + ".JPG", + ".m4v", + ".M4V", + ".mov", + ".MOV", + ".mp4", + ".MP4", + ".mta", + ".MTA", + ".png", + ".PNG", + ".tiff", + ".TIFF" + ], + "VerifyToSeason": [ + ". 2000", + ". 2001", + ". 2002", + ". 2003", + ". 2004", + ". 2005", + ". 2006", + ". 2007", + ". 2008", + ". 2009", + ". 2010", + ". 2011", + ". 2012", + ". 2013", + ". 2014", + ". 2015", + ". 2016", + ". 2017", + ". 2018", + ". 2019", + ". 2020", + ". 2021", + ". 2022", + ". 2023", + ". 2024", + ". 2025", + ". 2026", + ". 2027", + ". 2028", + ". 2029", + "=2000.0 Winter", + "=2002.1 Spring", + "=2002.4 Winter", + "=2003.0 Winter", + "=2003.1 Spring", + "=2003.3 Fall", + "=2003.4 Winter", + "=2004.0 Winter", + "=2005.1 Spring", + "=2005.2 Summer", + "=2005.3 Fall", + "=2005.4 Winter", + "=2006.0 Winter", + "=2006.1 Spring", + "=2006.3 Fall", + "=2007.0 Winter", + "=2007.2 Summer Logan Michael", + "=2007.2 Summer", + "=2007.3 Fall Logan Michael", + "=2007.4 Winter Logan Michael", + "=2008.0 Winter Logan Michael", + "=2008.1 Spring Logan Michael", + "=2008.2 Summer Logan Michael", + "=2008.2 Summer", + "=2008.3 Fall Logan Michael", + "=2009.0 Winter Logan Michael", + "=2009.0 Winter", + "=2009.1 Spring Logan Michael", + "=2009.1 Spring", + "=2009.2 Summer Logan Michael", + "=2009.2 Summer", + "=2009.3 Fall Logan Michael", + "=2009.3 Fall", + "=2009.4 Winter Logan Michael", + "=2009.4 Winter", + "=2010.0 Winter Logan Michael", + "=2010.0 Winter", + "=2010.1 Spring Logan Michael", + "=2010.1 Spring", + "=2010.2 Summer", + "=2010.3 Fall Logan Michael", + "=2010.3 Fall", + "=2010.4 Winter", + "=2011.0 Winter", + "=2011.1 Spring", + "=2011.2 Summer", + "=2011.3 Fall", + "=2011.4 Winter", + "=2012.0 Winter Chelsea 2012", + "=2012.0 Winter Chelsea", + "=2012.0 Winter", + "=2012.1 Spring Chelsea", + "=2012.1 Spring", + "=2012.2 Summer Chelsea", + "=2012.2 Summer", + "=2012.3 Fall Chelsea", + "=2012.3 Fall", + "=2012.4 Winter Chelsea", + "=2012.4 Winter", + "=2013.0 Winter Chelsea 2013", + "=2013.0 Winter Chelsea", + "=2013.0 Winter", + "=2013.1 Spring", + "=2013.2 Summer Chelsea", + "=2013.2 Summer", + "=2013.3 Fall Chelsea", + "=2013.3 Fall", + "=2013.4 Winter", + "=2014.0 Winter", + "=2014.1 Spring", + "=2014.2 Summer", + "=2014.3 Fall", + "=2014.4 Winter", + "=2015.0 Winter", + "=2015.1 Spring", + "=2015.2 Summer", + "=2015.3 Fall", + "=2015.4 Winter", + "=2016.0 Winter", + "=2016.1 Spring", + "=2016.2 Summer", + "=2016.3 Fall", + "=2016.4 Winter", + "=2017.1 Spring", + "=2017.2 Summer", + "=2017.3 Fall", + "=2017.4 Winter", + "=2018.0 Winter", + "=2018.1 Spring", + "=2018.3 Fall", + "=2018.4 Winter", + "=2019.0 Winter", + "=2019.1 Spring", + "=2019.2 Summer", + "=2019.3 Fall", + "=2019.4 Winter", + "=2020.0 Winter", + "=2020.1 Spring", + "=2020.2 Summer", + "=2020.3 Fall", + "=2020.4 Winter", + "=2021.1 Spring", + "=2021.2 Summer", + "=2021.3 Fall", + "=2021.4 Winter", + "=2022.0 Winter", + "=2022.1 Spring", + "Anthem 2015", + "April 2010", + "April 2013", + "December 2006", + "December 2010", + "Fall 2005", + "Fall 2015", + "Fall 2016", + "Fall 2017", + "Fall 2018", + "Fall 2019", + "Fall 2020", + "Fall 2021", + "February 2010", + "January 2015", + "July 2010", + "June 2010", + "Kids 2005", + "March 2013", + "May 2010", + "May 2011", + "May 2013", + "October 2005", + "October 2014", + "Spring 2013", + "Spring 2014", + "Spring 2016", + "Spring 2018", + "Spring 2019", + "Spring 2020", + "Summer 2011", + "Summer 2012", + "Summer 2013", + "Summer 2014", + "Summer 2015", + "Summer 2016", + "Summer 2017", + "Summer 2018", + "Summer 2020", + "Summer 2021", + "Winter 2015", + "Winter 2016", + "Winter 2017", + "Winter 2018", + "Winter 2019-2020", + "Winter 2020", + "zzz =2005.0 Winter Tracy Pictures", + "zzz =2005.1 Spring Tracy Pictures", + "zzz =2005.2 Summer Tracy Pictures", + "zzz =2005.3 Fall Tracy Pictures", + "zzz =2005.4 Winter Tracy Pictures", + "zzz =2006.1 Spring Tracy Pictures", + "zzz =2007.0 Winter Tracy Pictures", + "zzz =2007.2 Summer Tracy Pictures", + "zzz =2008.0 Winter Tracy Pictures", + "zzz =2008.2 Summer Tracy Pictures", + "zzz =2009.0 Winter Tracy Pictures", + "zzz =2009.2 Summer Tracy Pictures", + "zzz =2009.3 Fall Tracy Pictures", + "zzz =2009.4 Winter Tracy Pictures", + "zzz =2010.0 Winter Tracy Pictures", + "zzz =2010.1 Spring Tracy Pictures", + "zzz =2010.2 Summer Tracy Pictures", + "zzz =2010.3 Fall Tracy Pictures", + "zzz =2011.0 Winter Tracy Pictures", + "zzz =2011.1 Spring Tracy Pictures", + "zzz =2011.2 Summer Tracy Pictures", + "zzz =2011.3 Fall Tracy Pictures", + "zzz =2011.4 Winter Tracy Pictures", + "zzz =2012.0 Winter Tracy Pictures", + "zzz =2012.1 Spring Tracy Pictures", + "zzz =2012.2 Summer Tracy Pictures", + "zzz =2012.3 Fall Tracy Pictures", + "zzz =2012.4 Winter Tracy Pictures", + "zzz =2013.0 Winter Tracy Pictures", + "zzz =2013.1 Spring Tracy Pictures", + "zzz =2013.2 Summer Tracy Pictures", + "zzz =2013.3 Fall Tracy Pictures", + "zzz =2013.4 Winter Tracy Pictures", + "zzz =2014.0 Winter Tracy Pictures", + "zzz =2014.1 Spring Tracy Pictures", + "zzz =2014.2 Summer Tracy Pictures", + "zzz =2014.3 Fall Tracy Pictures", + "zzz =2014.4 Winter Tracy Pictures", + "zzz =2015.0 Winter Tracy Pictures" + ], + "Spelling": [ + "Bday|Birthday", + "Childrens|Children's", + "Darrens|Darren's", + "Febuary|February", + "Feburay|February", + "Frist|First", + "Goolgle|Google", + "Kristys|Kristy's", + "Micael's|Michael's", + "Origanls|Originals", + "Partion|Partition", + "Patrict|Patrick", + "Sebtember|September", + "ב|zzz" + ], + "Rename": [ + "=2012.0 Winter Chelsea 2012|=2012.0 Winter Chelsea", + "=2013.0 Winter Chelsea 2013|=2013.0 Winter Chelsea", + "2004 4th of July|4th of July 2004", + "2006 4th of July|4th of July 2006", + "2007 4th of July|4th of July 2007", + "2009 4th of July|4th of July 2009", + "2011 April|. 2011", + "3757 W Whitman|3757Whitman|3757Whitman|3757 W Whitman 2017", + "All Pictures from Wedding Originals|AllPicturesFromWeddingOriginals|AllPicturesFromWeddingOriginals|All Pictures from Wedding Originals 2006", + "Anthem2015|. 2015", + "April 2010|. 2011", + "April's Wedding|April'sWedding|April'sWedding|April's Wedding 2010", + "Arturo|ART|ART|Arturo 2002", + "asdf|ASDF|ASDF|asdf", + "AZ 2015|. 2015", + "AZ 2016|. 2016", + "AZ 2018|. 2018", + "AZ2016|. 2016", + "Baby Shower 2012|BabyShower2012|BabyShower2012|Chelsea Baby Shower 2012", + "Barrick Wedding|BarrickWedding|BarrickWedding|Barrick Wedding 2015", + "Blackberry 2009|. 2009", + "Blackberry 2010|. 2010", + "Blackberry 2011|. 2011", + "Broncos Game|BroncosGame|BroncosGame|Broncos Game 2010", + "Broncos Gme|Broncos Game 2010", + "Camp Shaver 2009|CampShaver2009|CampShaver2009|Jason Camp Shaver 2009", + "Chelsea's 2nd Birthday|Chelsea's2ndBirthday|Chelsea's2ndBirthday|Chelsea's 2nd Birthday 2014", + "Chelsea's 5th Birthday|Chelsea's5thBirthday|Chelsea's5thBirthday|Chelsea's 5th Birthday 2017", + "Chelsea's 7th Birthday|Chelsea's7thBirthday|Chelsea's7thBirthday|Chelsea's 7th Birthday 2018", + "Cliffs.Tanner 2015|Cliffs Tanner 2015", + "Crystal's Wedding|Crystal'sWedding|Crystal'sWedding|Crystal's Wedding 2003", + "Danny's Wedding|Danny'sWedding|Danny'sWedding|Danny's Wedding 2009", + "Darren's Camera|Darren'sCamera|Darren'sCamera|Darren's Camera 2006", + "Door images 2019|DoorImages2019|DoorImages2019|Door Images 2019", + "Engagement day|EngagementDay|EngagementDay|Engagement Day 2005", + "Engagement dy|Engagement Day 2005", + "Family 2000|. 2000", + "Family 2002|. 2002", + "Family 2003|. 2003", + "Family 2009|. 2009", + "Family Pictures 2006|zzz Family Pictures 2006", + "Family Pictures 2007|zzz Family Pictures 2007", + "Family Pictures 2011|zzz Family Pictures 2011", + "Family Pictures 2013|zzz Family Pictures 2013", + "Fathers Day 2015 Jemez|FathersDay2015Jemez|FathersDay2015Jemez|Fathers Day In Jemez 2015", + "Girl Scouts|Mackenzie Girl Scouts 2006", + "Grad Mike|GradMike|GradMike|Graduation Mike 2003", + "Grandma's Quilt|zzz Scanned Grandma's Quilt", + "Grandpa Ortega's Birthday|GrandpaOrtega'sBirthday|GrandpaOrtega'sBirthday|Grandpa Ortega's Birthday 2010", + "Grandpa Phares Services|GrandpaPharesServices|GrandpaPharesServices|Grandpa Phares Services 2012", + "GrandPrix 2004|zzz GrandPrix 2004", + "GrandPrix|zzz GrandPrix 2004", + "Herman Family Reunion|HermanFamilyReunion|HermanFamilyReunion|Herman Family Reunion 2008", + "Huval Wedding|HuvalWedding|HuvalWedding|Huval Wedding 2009", + "Jason & Kenzie Birthday Party 2010|Jason's 12th & Mackenzie's 10th Birthday Party 2010", + "Jason & Zack @Cliffs|JasonZackCliffs|JasonZackCliffs|Jason & Zack At Cliffs 2007", + "Jason 10 Birthday 2008|Jason's 10th Birthday 2008", + "Jason 10 birthday|Jason10Birthday|Jason10Birthday|Jason's 10th Birthday 2008", + "Jason 10th birthday|Jason10Birthday|Jason10Birthday|Jason's 10th Birthday 2008", + "Jason 12th Birthday 2010|Jason's 12th Birthday 2010", + "Jason 12th birthday|Jason12Birthday|Jason12Birthday|Jason's 12th Birthday 2010", + "Jason 13th bday|Jason13Birthday|Jason13Birthday|Jason's 13th Birthday 2011", + "Jason 13th Birthday 2011|Jason's 13th Birthday 2011", + "Jason 14th Birthday 2012|Jason's 14th Birthday 2012", + "Jason 14th Birthday|Jason14thBirthday|Jason14thBirthday|Jason's 14th Birthday 2012", + "Jason 2nd grade first day|Jason2ndGradeFirstDay|Jason2ndGradeFirstDay|Jason 2nd Grade First Day 2005", + "Jason 7 Birthday 2005|Jason's 7th Birthday 2005", + "Jason 7 birthday|Jason7Birthday|Jason7Birthday|Jason's 7th Birthday 2005", + "Jason 8 Birthday 2006|Jason's 8th Birthday 2006", + "Jason 8 birthday|Jason8Birthday|Jason8Birthday|Jason's 8th Birthday 2006", + "Jason 9th Birthday 2007|Jason's 9th Birthday 2007", + "Jason 9th birthday|Jason9Birthday|Jason9Birthday|Jason's 9th Birthday 2007", + "Jason first day kindergarten|JasonFirstDayKindergarten|JasonFirstDayKindergarten|Jason First Day Kindergarten 2003", + "Jason's camera work|Jason'sCameraWork|Jason'sCameraWork|Jason's Camera Work 2003", + "Jason's Collar Bone|Jason'sCollarBone|Jason'sCollarBone|Jason's Collar Bone 2008", + "Jason's glasses|Jason'sGlasses|Jason'sGlasses|Jason's Glasses 2006", + "Jason's Guitar|Jason'sGuitar|Jason'sGuitar|Jason's Guitar 2008", + "Jason's Teeth|Jason'sTeeth|Jason'sTeeth|Jason's Teeth 2004", + "Jason&Zack @Cliffs|Jason & Zack At Cliffs 2007", + "Jemez 9-08|Jemez08|Jemez08|Jemez 2008", + "Jemez 9-09|Jemez09|Jemez09|Jemez 2009", + "Jeremiah's Birthday|Jeremiah'sBirthday|Jeremiah'sBirthday|Jeremiah's Birthday 2008", + "Jeremiah's Christmas|Jeremiah'sChristmas|Jeremiah'sChristmas|Jeremiah's Christmas 2008", + "Johnny Graduation|JohnnyGraduation|JohnnyGraduation|Johnny Graduation 2007", + "Johnny's award|Johnny'sAward|Johnny'sAward|Johnny's Award 2007", + "Johnny's Hair|Johnny'sHair2008|Johnny'sHair2008|Johnny's Hair 2008", + "Johnny's Race|Johnny'sRace|Johnny'sRace|Johnny's Race 2006", + "Kids PJ Pants|KidsPJPants|KidsPJPants|Kids PJ Pants 2006", + "Kids School Pictures|KidsSchoolPictures|KidsSchoolPictures|Kids School Pictures 2004", + "Kids|KDS|KDS|Kids 2005", + "Kristy Parents Wedding|KristyParentsWedding|KristyParentsWedding|Kristy Parents Wedding 2005", + "Kristy|KRS|KRS|Kristy 2002", + "LAHS Reunion|LAHSReunion|LAHSReunion|LAHS Reunion 2014", + "Logan 5th Birthday 2012|Logan's 5th Birthday 2012", + "Logan 5th Birthday|Logan5thBirthday|Logan5thBirthday|Logan's 5th Birthday 2012", + "Logan Preschool Graduation|LoganPreschoolGraduation|LoganPreschoolGraduation|Logan Preschool Graduation 2013", + "Logan Valentines Party|LoganValentinesParty|LoganValentinesParty|Logan Valentines Party 2013", + "Logan Vegas|LoganVegas|LoganVegas|Logan Vegas 2016", + "Logan's 10th Birthday|Logan's10thBirthday|Logan's10thBirthday|Logan's 10th Birthday 2017", + "Logan's 11th & Chelsea's 6th Birthday|Logan's11th&Chelsea's6thBirthday|Logan's11th&Chelsea's6thBirthday|Logan's 11th & Chelsea's 6th Birthday 2018", + "Logan's 12th Birthday|Logan's12thBirthday|Logan's12thBirthday|Logan's 12th Birthday 2019", + "Logan's 3rd Birthday|Logan's3rdBirthday|Logan's3rdBirthday|Logan's 3rd Birthday 2010", + "Logan's 4th Birthday|Logan's4thBirthday|Logan's4thBirthday|Logan's 4th Birthday 2011", + "Logan's 6th & Chelsea's 1st Birthday|Logan's6th&Chelsea's1stBirthday|Logan's6th&Chelsea's1stBirthday|Logan's 6th & Chelsea's 1st Birthday 2013", + "Logan's 7th & Chelsea's 2nd Birthday Party|Logan's7th&Chelsea's2ndBirthdayParty|Logan's7th&Chelsea's2ndBirthdayParty|Logan's 7th & Chelsea's 2nd Birthday Party 2014", + "Logan's 7th Birthday|Logan's7thBirthday|Logan's7thBirthday|Logan's 7th Birthday 2014", + "Logan's 8th and Chelsea's 3rd Birthday|Logan's8thAndChelsea's3rdBirthday|Logan's8thAndChelsea's3rdBirthday|Logan's 8th and Chelsea's 3rd Birthday 2015", + "Logan's 9th & Chelsea's 4th Birthday|Logan's9th&Chelsea's4thBirthday|Logan's9th&Chelsea's4thBirthday|Logan's 9th & Chelsea's 4th Birthday 2016", + "Mackara Wedding|MackaraWedding|MackaraWedding|Mackara Wedding 2009", + "Mackenzie 10 Birthday 2010|Mackenzie's 10th Birthday 2010", + "Mackenzie 10 Birthday|Mackenzie10Birthday|Mackenzie10Birthday|Mackenzie's 10th Birthday 2010", + "Mackenzie 11th bday|Mackenzie11thBirthday|Mackenzie11thBirthday|Mackenzie's 11th Birthday 2011", + "Mackenzie 11th Birthday 2011|Mackenzie's 11th Birthday 2011", + "Mackenzie 12 Birthday 2012|Mackenzie's 12th Birthday 2012", + "Mackenzie 12 Birthday|Mackenzie12Birthday|Mackenzie12Birthday|Mackenzie's 12th Birthday 2012", + "Mackenzie 13th Birthday 2013|Mackenzie's 13th Birthday 2013", + "Mackenzie 13th Birthday|Mackenzie13thBirthday|Mackenzie13thBirthday|Mackenzie's 13th Birthday 2013", + "Mackenzie 14 Birthday 2014|Mackenzie's 14 Birthday 2014", + "Mackenzie 14 Birthday|Mackenzie14Birthday|Mackenzie14Birthday|Mackenzie's 14th Birthday 2014", + "Mackenzie 15 Birthday 2015|Mackenzie's 15th Birthday 2015", + "Mackenzie 15 Birthday|Mackenzie15Birthday|Mackenzie15Birthday|Mackenzie's 15th Birthday 2015", + "Mackenzie 4 birthday 2004|Mackenzie's 4th Birthday 2004", + "Mackenzie 4 birthday|Mackenzie4Birthday|Mackenzie4Birthday|Mackenzie's 4th Birthday 2004", + "Mackenzie 5 birthday 2005|Mackenzie's 5th Birthday 2005", + "Mackenzie 5 birthday|Mackenzie5Birthday|Mackenzie5Birthday|Mackenzie's 5th Birthday 2005", + "Mackenzie 5th Grade Graduation|Mackenzie5thGradeGraduation|Mackenzie5thGradeGraduation|Mackenzie 5th Grade Graduation 2010", + "Mackenzie 6 birthday 2006|Mackenzie's 6th Birthday 2006", + "Mackenzie 6 birthday|Mackenzie6Birthday|Mackenzie6Birthday|Mackenzie's 6th Birthday 2006", + "Mackenzie 7 birthday 2007|Mackenzie's 7th Birthday 2007", + "Mackenzie 7 birthday|Mackenzie7Birthday|Mackenzie7Birthday|Mackenzie's 7th Birthday 2007", + "Mackenzie 8 birthday 2008|Mackenzie's 8 Birthday 2008", + "Mackenzie 8 birthday|Mackenzie8Birthday|Mackenzie8Birthday|Mackenzie's 8 Birthday 2008", + "Mackenzie 9 Birthday 2009|Mackenzie's 9th Birthday 2009", + "Mackenzie 9 Birthday|Mackenzie9Birthday|Mackenzie9Birthday|Mackenzie's 9th Birthday 2009", + "Mackenzie Birthday 2017|Mackenzie's 17th Birthday 2017", + "Mackenzie Birthday|Mackenzie's 17th Birthday 2017", + "Mackenzie CA 2016|Mackenzie's 16th Birthday CA 2016", + "Mackenzie End of Year Band Concert 2012|MackenzieEndOfYearBandConcert2012|MackenzieEndOfYearBandConcert2012|Mackenzie Band Concert 2012", + "Mackenzie Surgery|MackenzieSurgery|MackenzieSurgery|Mackenzie Surgery 2009", + "Mackenzie Volleyball|MackenzieVolleyball|MackenzieVolleyball|Mackenzie Volleyball 2012", + "Mackenzie's 14 Birthday 2014|Mackenzie's 14th Birthday 2014", + "Mackenzie's 8 Birthday 2008|Mackenzie's 8th Birthday 2008", + "Mackenzie's 8 Birthday|Mackenzie8Birthday|Mackenzie8Birthday|Mackenzie's 8th Birthday 2008", + "Mackenzie's 8th Birthday|Mackenzie8Birthday|Mackenzie8Birthday|Mackenzie's 8th Birthday 2008", + "Mackenzie's first tooth|Mackenzie'sFirstTooth|Mackenzie'sFirstTooth|Mackenzie's First Tooth 2006", + "Mackenzie's Picture taking|Mackenzie'sPictureTaking|Mackenzie'sPictureTaking|Mackenzie's Picture taking 2011", + "Mandy's Dogs|Mandy'sDogs|Mandy'sDogs|Mandy's Dogs 2008", + "Mandy's Photos|zzz Mandy's Photos 2010", + "Matt's Baby Shower|Matt'sBabyShower|Matt'sBabyShower|Matt's Baby Shower 2008", + "Memorial Day|MemorialDay|MemorialDay|Memorial Day 2015", + "Mom's stuff 2014|. 2004", + "Mom's stuff|. 2004", + "Mother Cabrini Shrine|MotherCabriniShrine|MotherCabriniShrine|Mother Cabrini Shrine 2010", + "Motorcycles 2010|zzz Motorcycles 2010", + "Motorcycles 2013|zzz Motorcycles 2013", + "Motorcycles 2014|zzz Motorcycles 2014", + "Museum 2013|Museum 2004", + "museum012404|Museum 2004", + "Navajo Lake|NavajoLake|NavajoLake|Navajo Lake 2006", + "New Car|zzz Vericruz 2011", + "New folder|Mackenzie 2017", + "New Puppy|NewPuppy|NewPuppy|New Puppy Bandit 2010", + "Nkotb|NKT|NKT|NKOTB 2011", + "Parents trip to Alaska|zzz Parents trip to Alaska", + "Parents Wedding Picture|ParentsWeddingPicture|ParentsWeddingPicture|Parents Wedding Picture 1975", + "Parents Yard 2002|zzz Parents Yard 2002", + "Parents Yard|ParentsYard|ParentsYard|zzz Parents Yard 2002", + "Patrick|zzz Patrick", + "Phares 60th Anniversary|Phares60thAnniversary|Phares60thAnniversary|Phares 60th Anniversary 2010", + "Phares Family Pictures 2018|zzz Phares Family Pictures 2018", + "Phares Slides|zzz Phares Slides", + "Phone Pictures 2010|. 2010", + "Phone Pictures 2011|. 2011", + "Phone Pictures 2012|. 2012", + "Phone Pictures 2013|. 2013", + "Piper|PPR|PPR|Piper 2015", + "Polar Express|PolarExpress|PolarExpress|Polar Express 2010", + "Portrait Innovations April 2008|zzz Portrait Innovations April 2008", + "Portrait Innovations Files 2007|zzz Portrait Innovations Files 2007", + "Portrait Innovations June 08|zzz Portrait Innovations June 2008", + "Portrait Innovations June 2008|zzz Portrait Innovations June 2008", + "Portrait Innovations March 2012|zzz Portrait Innovations March 2012", + "Pueblo Lake|PuebloLake|PuebloLake|Pueblo Lake 2010", + "Puerto Rico|PuertoRico|PuertoRico|Puerto Rico 2006", + "Rex Memorial|zzz Rex Memorial", + "Scaned pictrues of kids|zzz Scanned Pictures Of Kids", + "Scanned Grandma's Quilt|zzz Scanned Grandma's Quilt", + "Scanned Pictrues Of Kids|zzz Scanned Pictures Of Kids", + "Scanned Prints|zzz Scanned Prints", + "Seattle|STL|STL|Seattle 2003", + "Slide in Name Order Originals (622)|zzz Slide in Name Order Originals (622)", + "Snow boarding|SnowBoarding|SnowBoarding|Snow boarding 2000", + "Snow Storm|SnowStorm|SnowStorm|Snow Storm 2006", + "Sophia's Birthday Party|Sophia'sBirthdayParty|Sophia'sBirthdayParty|Sophia's Birthday Party 2009", + "The guys house|TheGuysHouse|TheGuysHouse|The guys house 2000", + "Track 2013|Jason & Mackenzie Track 2013", + "Tracy Picture Partion|zzz Tracy Picture Partition", + "Tracy Picture Partition|zzz Tracy Picture Partition", + "Tracy Pictures 2005|zzz Tracy Pictures 2005", + "Tracy Pictures 2006|zzz Tracy Pictures 2006", + "Tracy Pictures 2007|zzz Tracy Pictures 2007", + "Tracy Pictures 2008|zzz Tracy Pictures 2008", + "Tracy Pictures 2009|zzz Tracy Pictures 2009", + "Tracy Pictures 2010|zzz Tracy Pictures 2010", + "Tracy Pictures 2011|zzz Tracy Pictures 2011", + "Tracy Pictures 2012|zzz Tracy Pictures 2012", + "Tracy Pictures 2013 Jan-July|zzz Tracy Pictures 2013", + "Tracy Pictures 2013 July- Dec|zzz Tracy Pictures 2013", + "Tracy Pictures 2014|zzz Tracy Pictures 2014", + "Tracy Pictures 2015|zzz Tracy Pictures 2015", + "Tracy's Wedding|Tracy'sWedding|Tracy'sWedding|Tracy's Wedding 2002", + "Trip to Colorado 10 2002|Trip to Colorado October 2002", + "Trip to Colorado 10-1-02|Trip to Colorado October 2002", + "Trip to Colorado 6-1-02|Trip to Colorado June 2002", + "Tub 2002|zzz Tub 2002", + "Tub|zzz Tub 2002", + "Vericruz 2011|zzz Vericruz 2011", + "Washington DC|WashingtonDC|WashingtonDC|Washington DC 2010", + "Winter 2015-2016|Winter 2016", + "X Games|XGames|XGames|X Games 2011" + ], + "RenameB": [ + "/zzz Phares Slides/Slides 2015-06-10/Magazine 01|/zzz Phares Slides/Magazine 01", + "/zzz Phares Slides/Slides 2015-06-10/Magazine 02|/zzz Phares Slides/Magazine 02", + "/zzz Phares Slides/Slides 2015-06-10/Magazine 03|/zzz Phares Slides/Magazine 03", + "/zzz Phares Slides/Slides 2015-06-10/Magazine 04|/zzz Phares Slides/Magazine 04", + "/zzz Phares Slides/Slides 2015-06-10/Magazine 05|/zzz Phares Slides/Magazine 05", + "/zzz Phares Slides/Slides 2015-06-10/Magazine 06|/zzz Phares Slides/Magazine 06", + "/zzz Phares Slides/Slides 2015-06-10/Magazine 07|/zzz Phares Slides/Magazine 07", + "/zzz Phares Slides/Slides 2015-06-10/Magazine 08|/zzz Phares Slides/Magazine 08", + "/zzz Phares Slides/Slides 2015-06-10/Magazine 09|/zzz Phares Slides/Magazine 09", + "/zzz Phares Slides/Slides 2015-06-10/Magazine 10|/zzz Phares Slides/Magazine 10", + "/zzz Phares Slides/Slides 2017-03-14/Magazine 11|/zzz Phares Slides/Magazine 11", + "/zzz Phares Slides/Slides 2017-03-14/Magazine 12|/zzz Phares Slides/Magazine 12", + "/zzz Phares Slides/Slides 2017-03-14/Magazine 13|/zzz Phares Slides/Magazine 13", + "/zzz Phares Slides/Slides 2017-03-14/Magazine 14|/zzz Phares Slides/Magazine 14", + "/zzz Phares Slides/Slides 2017-03-14/Magazine 15|/zzz Phares Slides/Magazine 15", + "/zzz Phares Slides/Slides 2017-03-14/Magazine 16|/zzz Phares Slides/Magazine 16", + "/zzz Phares Slides/Slides 2017-03-14/Magazine 17|/zzz Phares Slides/Magazine 17", + "/zzz Phares Slides/Slides 2017-03-14/Magazine 18|/zzz Phares Slides/Magazine 18", + "/zzz Phares Slides/Slides 2017-03-14/Magazine 19|/zzz Phares Slides/Magazine 19", + "/zzz Phares Slides/Slides 2017-03-14/Magazine 20|/zzz Phares Slides/Magazine 20", + "/zzz Phares Slides/Slides 2017-03-14/Magazine 21|/zzz Phares Slides/Magazine 21", + "/zzz Phares Slides/Slides 2017-03-18/Magazine 22|/zzz Phares Slides/Magazine 22", + "/zzz Phares Slides/Slides 2017-03-18/Magazine 23|/zzz Phares Slides/Magazine 23", + "/zzz Phares Slides/Slides 2017-03-18/Magazine 24|/zzz Phares Slides/Magazine 24", + "/zzz Phares Slides/Slides 2017-03-18/Magazine 25|/zzz Phares Slides/Magazine 25", + "/zzz Phares Slides/Slides 2017-10-08/Magazine 26|/zzz Phares Slides/Magazine 26", + "/zzz Phares Slides/Slides 2017-10-08/Magazine 27|/zzz Phares Slides/Magazine 27", + "/zzz Phares Slides/Slides 2017-10-08/Magazine 28|/zzz Phares Slides/Magazine 28", + "/zzz Phares Slides/Slides 2017-10-08/Magazine 29|/zzz Phares Slides/Magazine 29", + "/zzz Phares Slides/Slides 2017-10-08/Magazine 30|/zzz Phares Slides/Magazine 30", + "/zzz Phares Slides/Slides 2017-10-08/Magazine 31|/zzz Phares Slides/Magazine 31", + "/zzz Phares Slides/Slides 2017-10-08/Magazine 32|/zzz Phares Slides/Magazine 32", + "/zzz Phares Slides/Slides 2017-10-08/Magazine 33|/zzz Phares Slides/Magazine 33", + "/zzz Phares Slides/Slides 2017-10-08/Magazine 34|/zzz Phares Slides/Magazine 34", + "/zzz Phares Slides/Slides 2017-10-08/Magazine 35|/zzz Phares Slides/Magazine 35", + "/zzz Phares Slides/Slides 2017-10-08/Magazine 36|/zzz Phares Slides/Magazine 36", + "/zzz Phares Slides/Slides 2017-10-08/Info 01 - 12|/zzz Phares Slides/Info 01 - 12", + "/zzz Phares Slides/Slides 2017-10-08/Info 13 - 22|/zzz Phares Slides/Info 13 - 22", + "/zzz Phares Slides/Slides 2017-10-08/Info 23 - 24|/zzz Phares Slides/Info 23 - 24", + "/zzz Tracy Picture Partition/2005/April 2005|/zzz Tracy Pictures 2005/April 2005", + "/zzz Tracy Picture Partition/2005/August 2005/August 30 2005|/zzz Tracy Pictures 2005/August 2005/August 30 2005", + "/zzz Tracy Picture Partition/2005/August 2005/August 31 2005|/zzz Tracy Pictures 2005/August 2005/August 31 2005", + "/zzz Tracy Picture Partition/2005/December 2005/December 16 2005|/zzz Tracy Pictures 2005/December 2005/December 16 2005", + "/zzz Tracy Picture Partition/2005/December 2005/December 17 2005|/zzz Tracy Pictures 2005/December 2005/December 17 2005", + "/zzz Tracy Picture Partition/2005/December 2005/December 18 2005|/zzz Tracy Pictures 2005/December 2005/December 18 2005", + "/zzz Tracy Picture Partition/2005/December 2005/December 20 2005|/zzz Tracy Pictures 2005/December 2005/December 20 2005", + "/zzz Tracy Picture Partition/2005/December 2005/December 23 2005|/zzz Tracy Pictures 2005/December 2005/December 23 2005", + "/zzz Tracy Picture Partition/2005/December 2005/December 26 2005|/zzz Tracy Pictures 2005/December 2005/December 26 2005", + "/zzz Tracy Picture Partition/2005/December 2005/December 27 2005|/zzz Tracy Pictures 2005/December 2005/December 27 2005", + "/zzz Tracy Picture Partition/2005/December 2005/December 9 2005|/zzz Tracy Pictures 2005/December 2005/December 9 2005", + "/zzz Tracy Picture Partition/2005/December 2005|/zzz Tracy Pictures 2005/December 2005", + "/zzz Tracy Picture Partition/2005/July 2005/July 1 2005|/zzz Tracy Pictures 2005/July 2005/July 1 2005", + "/zzz Tracy Picture Partition/2005/July 2005/July 2 2005|/zzz Tracy Pictures 2005/July 2005/July 2 2005", + "/zzz Tracy Picture Partition/2005/July 2005/July 4 2005|/zzz Tracy Pictures 2005/July 2005/July 4 2005", + "/zzz Tracy Picture Partition/2005/July 2005|/zzz Tracy Pictures 2005/July 2005", + "/zzz Tracy Picture Partition/2005/June 2005/June 28 2005|/zzz Tracy Pictures 2005/June 2005/June 28 2005", + "/zzz Tracy Picture Partition/2005/June 2005/June 29 2005|/zzz Tracy Pictures 2005/June 2005/June 29 2005", + "/zzz Tracy Picture Partition/2005/June 2005/June 30 2005|/zzz Tracy Pictures 2005/June 2005/June 30 2005", + "/zzz Tracy Picture Partition/2005/March 2005|/zzz Tracy Pictures 2005/March 2005", + "/zzz Tracy Picture Partition/2005/MAy 2005|/zzz Tracy Pictures 2005/MAy 2005", + "/zzz Tracy Picture Partition/2005/November 2005/November 13 2005|/zzz Tracy Pictures 2005/November 2005/November 13 2005", + "/zzz Tracy Picture Partition/2005/November 2005/November 16 2005|/zzz Tracy Pictures 2005/November 2005/November 16 2005", + "/zzz Tracy Picture Partition/2005/November 2005/November 18 2005|/zzz Tracy Pictures 2005/November 2005/November 18 2005", + "/zzz Tracy Picture Partition/2005/November 2005/November 20 2005|/zzz Tracy Pictures 2005/November 2005/November 20 2005", + "/zzz Tracy Picture Partition/2005/November 2005/November 23 2005|/zzz Tracy Pictures 2005/November 2005/November 23 2005", + "/zzz Tracy Picture Partition/2005/November 2005/November 24 2005|/zzz Tracy Pictures 2005/November 2005/November 24 2005", + "/zzz Tracy Picture Partition/2005/November 2005/November 28 2005|/zzz Tracy Pictures 2005/November 2005/November 28 2005", + "/zzz Tracy Picture Partition/2005/November 2005/November 30 2005|/zzz Tracy Pictures 2005/November 2005/November 30 2005", + "/zzz Tracy Picture Partition/2005/November 2005/November 4 2005|/zzz Tracy Pictures 2005/November 2005/November 4 2005", + "/zzz Tracy Picture Partition/2005/November 2005/November 5 2005|/zzz Tracy Pictures 2005/November 2005/November 5 2005", + "/zzz Tracy Picture Partition/2005/November 2005/November 6 2005|/zzz Tracy Pictures 2005/November 2005/November 6 2005", + "/zzz Tracy Picture Partition/2005/November 2005|/zzz Tracy Pictures 2005/November 2005", + "/zzz Tracy Picture Partition/2005/October 2005/October 11 2005|/zzz Tracy Pictures 2005/October 2005/October 11 2005", + "/zzz Tracy Picture Partition/2005/October 2005/October 17 2005|/zzz Tracy Pictures 2005/October 2005/October 17 2005", + "/zzz Tracy Picture Partition/2005/October 2005/October 30 2005|/zzz Tracy Pictures 2005/October 2005/October 30 2005", + "/zzz Tracy Picture Partition/2005/October 2005/October 4 2005|/zzz Tracy Pictures 2005/October 2005/October 4 2005", + "/zzz Tracy Picture Partition/2005/October 2005/October 6 2005|/zzz Tracy Pictures 2005/October 2005/October 6 2005", + "/zzz Tracy Picture Partition/2005/October 2005|/zzz Tracy Pictures 2005/October 2005", + "/zzz Tracy Picture Partition/2005/September 2005/September 10 2005|/zzz Tracy Pictures 2005/September 2005/September 10 2005", + "/zzz Tracy Picture Partition/2005/September 2005/September 2 2005|/zzz Tracy Pictures 2005/September 2005/September 2 2005", + "/zzz Tracy Picture Partition/2005/September 2005/September 20 2005|/zzz Tracy Pictures 2005/September 2005/September 20 2005", + "/zzz Tracy Picture Partition/2005/September 2005/September 25 2005|/zzz Tracy Pictures 2005/September 2005/September 25 2005", + "/zzz Tracy Picture Partition/2005/September 2005/September 26 2005|/zzz Tracy Pictures 2005/September 2005/September 26 2005", + "/zzz Tracy Picture Partition/2005/September 2005/September 28 2005|/zzz Tracy Pictures 2005/September 2005/September 28 2005", + "/zzz Tracy Picture Partition/2005/September 2005/September 3 2005|/zzz Tracy Pictures 2005/September 2005/September 3 2005", + "/zzz Tracy Picture Partition/2005/September 2005/September 4 2005|/zzz Tracy Pictures 2005/September 2005/September 4 2005", + "/zzz Tracy Picture Partition/2005/September 2005/September 5 2005|/zzz Tracy Pictures 2005/September 2005/September 5 2005", + "/zzz Tracy Picture Partition/2005/September 2005/September 6 2005|/zzz Tracy Pictures 2005/September 2005/September 6 2005", + "/zzz Tracy Picture Partition/2005/September 2005/September 7 2005|/zzz Tracy Pictures 2005/September 2005/September 7 2005", + "/zzz Tracy Picture Partition/2005/September 2005/September 8 2005|/zzz Tracy Pictures 2005/September 2005/September 8 2005", + "/zzz Tracy Picture Partition/2005/September 2005|/zzz Tracy Pictures 2005/September 2005", + "/zzz Tracy Picture Partition/2006/April 2006/April 12 2006|/zzz Tracy Pictures 2006/April 2006/April 12 2006", + "/zzz Tracy Picture Partition/2006/April 2006/April 14 2006|/zzz Tracy Pictures 2006/April 2006/April 14 2006", + "/zzz Tracy Picture Partition/2006/April 2006/April 16 2006|/zzz Tracy Pictures 2006/April 2006/April 16 2006", + "/zzz Tracy Picture Partition/2006/April 2006/April 17 2006|/zzz Tracy Pictures 2006/April 2006/April 17 2006", + "/zzz Tracy Picture Partition/2006/April 2006/April 18 2006|/zzz Tracy Pictures 2006/April 2006/April 18 2006", + "/zzz Tracy Picture Partition/2006/April 2006/April 19 2006|/zzz Tracy Pictures 2006/April 2006/April 19 2006", + "/zzz Tracy Picture Partition/2006/April 2006/April 20 2006|/zzz Tracy Pictures 2006/April 2006/April 20 2006", + "/zzz Tracy Picture Partition/2006/April 2006/April 21 2006|/zzz Tracy Pictures 2006/April 2006/April 21 2006", + "/zzz Tracy Picture Partition/2006/April 2006/April 23 2006|/zzz Tracy Pictures 2006/April 2006/April 23 2006", + "/zzz Tracy Picture Partition/2006/April 2006/April 24 2006|/zzz Tracy Pictures 2006/April 2006/April 24 2006", + "/zzz Tracy Picture Partition/2006/April 2006/April 25 2006|/zzz Tracy Pictures 2006/April 2006/April 25 2006", + "/zzz Tracy Picture Partition/2006/April 2006/April 3 2006|/zzz Tracy Pictures 2006/April 2006/April 3 2006", + "/zzz Tracy Picture Partition/2006/April 2006/April 6 2006|/zzz Tracy Pictures 2006/April 2006/April 6 2006", + "/zzz Tracy Picture Partition/2006/March 2006/March 27 2006|/zzz Tracy Pictures 2006/March 2006/March 27 2006", + "/zzz Tracy Picture Partition/2006/March 2006/March 28 2006|/zzz Tracy Pictures 2006/March 2006/March 28 2006", + "/zzz Tracy Picture Partition/2006/March 2006/March 29 2006|/zzz Tracy Pictures 2006/March 2006/March 29 2006", + "/zzz Tracy Picture Partition/2006/March 2006/March 30 2006|/zzz Tracy Pictures 2006/March 2006/March 30 2006", + "/zzz Tracy Picture Partition/2007/August 2007/August 10 2007|/zzz Tracy Pictures 2007/August 2007/August 10 2007", + "/zzz Tracy Picture Partition/2007/August 2007/August 6 2007|/zzz Tracy Pictures 2007/August 2007/August 6 2007", + "/zzz Tracy Picture Partition/2007/August 2007/August 7 2007|/zzz Tracy Pictures 2007/August 2007/August 7 2007", + "/zzz Tracy Picture Partition/2007/February 2007/February 10 2007|/zzz Tracy Pictures 2007/February 2007/February 10 2007", + "/zzz Tracy Picture Partition/2007/February 2007/February 13 2007|/zzz Tracy Pictures 2007/February 2007/February 13 2007", + "/zzz Tracy Picture Partition/2007/February 2007/February 15 2007|/zzz Tracy Pictures 2007/February 2007/February 15 2007", + "/zzz Tracy Picture Partition/2007/February 2007/February 16 2007|/zzz Tracy Pictures 2007/February 2007/February 16 2007", + "/zzz Tracy Picture Partition/2007/February 2007/February 19 2007|/zzz Tracy Pictures 2007/February 2007/February 19 2007", + "/zzz Tracy Picture Partition/2007/Febuary 2007/Febuary 10 2007|/zzz Tracy Pictures 2007/Febuary 2007/Febuary 10 2007", + "/zzz Tracy Picture Partition/2007/Febuary 2007/Febuary 13 2007|/zzz Tracy Pictures 2007/Febuary 2007/Febuary 13 2007", + "/zzz Tracy Picture Partition/2007/Febuary 2007/Febuary 15 2007|/zzz Tracy Pictures 2007/Febuary 2007/Febuary 15 2007", + "/zzz Tracy Picture Partition/2007/Febuary 2007/Febuary 16 2007|/zzz Tracy Pictures 2007/Febuary 2007/Febuary 16 2007", + "/zzz Tracy Picture Partition/2007/Febuary 2007/Febuary 19 2007|/zzz Tracy Pictures 2007/Febuary 2007/Febuary 19 2007", + "/zzz Tracy Picture Partition/2007/September 2007/September 5 2007|/zzz Tracy Pictures 2007/September 2007/September 5 2007", + "/zzz Tracy Picture Partition/2007/September 2007|/zzz Tracy Pictures 2007/September 2007", + "/zzz Tracy Picture Partition/2008|/zzz Tracy Pictures 2008", + "/zzz Tracy Picture Partition/2009/December 2009/December 1 2009|/zzz Tracy Pictures 2009/December 2009/December 1 2009", + "/zzz Tracy Picture Partition/2009/December 2009/December 11 2009|/zzz Tracy Pictures 2009/December 2009/December 11 2009", + "/zzz Tracy Picture Partition/2009/December 2009/December 12 2009|/zzz Tracy Pictures 2009/December 2009/December 12 2009", + "/zzz Tracy Picture Partition/2009/December 2009/December 16 2009|/zzz Tracy Pictures 2009/December 2009/December 16 2009", + "/zzz Tracy Picture Partition/2009/December 2009/December 18 2009|/zzz Tracy Pictures 2009/December 2009/December 18 2009", + "/zzz Tracy Picture Partition/2009/December 2009/December 20 2009|/zzz Tracy Pictures 2009/December 2009/December 20 2009", + "/zzz Tracy Picture Partition/2009/December 2009/December 21 2009|/zzz Tracy Pictures 2009/December 2009/December 21 2009", + "/zzz Tracy Picture Partition/2009/December 2009/December 22 2009|/zzz Tracy Pictures 2009/December 2009/December 22 2009", + "/zzz Tracy Picture Partition/2009/December 2009/December 25 2009|/zzz Tracy Pictures 2009/December 2009/December 25 2009", + "/zzz Tracy Picture Partition/2009/December 2009/December 3 2009|/zzz Tracy Pictures 2009/December 2009/December 3 2009", + "/zzz Tracy Picture Partition/2009/December 2009/December 31 2009|/zzz Tracy Pictures 2009/December 2009/December 31 2009", + "/zzz Tracy Picture Partition/2009/February 2009/February 1 2009|/zzz Tracy Pictures 2009/February 2009/February 1 2009", + "/zzz Tracy Picture Partition/2009/February 2009/February 18 2009|/zzz Tracy Pictures 2009/February 2009/February 18 2009", + "/zzz Tracy Picture Partition/2009/February 2009/February 2 2009|/zzz Tracy Pictures 2009/February 2009/February 2 2009", + "/zzz Tracy Picture Partition/2009/February 2009|/zzz Tracy Pictures 2009/February 2009", + "/zzz Tracy Picture Partition/2009/Febuary 2009/Febuary 1 2009|/zzz Tracy Pictures 2009/Febuary 2009/Febuary 1 2009", + "/zzz Tracy Picture Partition/2009/Febuary 2009/Febuary 18 2009|/zzz Tracy Pictures 2009/Febuary 2009/Febuary 18 2009", + "/zzz Tracy Picture Partition/2009/Febuary 2009/Febuary 2 2009|/zzz Tracy Pictures 2009/Febuary 2009/Febuary 2 2009", + "/zzz Tracy Picture Partition/2009/Febuary 2009|/zzz Tracy Pictures 2009/Febuary 2009", + "/zzz Tracy Picture Partition/2009/January 2009/January 12 2009|/zzz Tracy Pictures 2009/January 2009/January 12 2009", + "/zzz Tracy Picture Partition/2009/January 2009/January 13 2009|/zzz Tracy Pictures 2009/January 2009/January 13 2009", + "/zzz Tracy Picture Partition/2009/January 2009/January 14 2009|/zzz Tracy Pictures 2009/January 2009/January 14 2009", + "/zzz Tracy Picture Partition/2009/January 2009/January 15 2009|/zzz Tracy Pictures 2009/January 2009/January 15 2009", + "/zzz Tracy Picture Partition/2009/January 2009/January 19 2009|/zzz Tracy Pictures 2009/January 2009/January 19 2009", + "/zzz Tracy Picture Partition/2009/January 2009/January 27 2009|/zzz Tracy Pictures 2009/January 2009/January 27 2009", + "/zzz Tracy Picture Partition/2009/January 2009/January 28 2009|/zzz Tracy Pictures 2009/January 2009/January 28 2009", + "/zzz Tracy Picture Partition/2009/January 2009/January 29 2009|/zzz Tracy Pictures 2009/January 2009/January 29 2009", + "/zzz Tracy Picture Partition/2009/January 2009/January 4 2009|/zzz Tracy Pictures 2009/January 2009/January 4 2009", + "/zzz Tracy Picture Partition/2009/January 2009/January 6 2009|/zzz Tracy Pictures 2009/January 2009/January 6 2009", + "/zzz Tracy Picture Partition/2009/January 2009/January 9 2009|/zzz Tracy Pictures 2009/January 2009/January 9 2009", + "/zzz Tracy Picture Partition/2009/January 2009|/zzz Tracy Pictures 2009/January 2009", + "/zzz Tracy Picture Partition/2009/November 2009/November 17 2009|/zzz Tracy Pictures 2009/November 2009/November 17 2009", + "/zzz Tracy Picture Partition/2009/November 2009/November 18 2009|/zzz Tracy Pictures 2009/November 2009/November 18 2009", + "/zzz Tracy Picture Partition/2009/November 2009/November 2 2009|/zzz Tracy Pictures 2009/November 2009/November 2 2009", + "/zzz Tracy Picture Partition/2009/November 2009/November 21 2009|/zzz Tracy Pictures 2009/November 2009/November 21 2009", + "/zzz Tracy Picture Partition/2009/November 2009/November 22 2009|/zzz Tracy Pictures 2009/November 2009/November 22 2009", + "/zzz Tracy Picture Partition/2009/November 2009/November 23 2009|/zzz Tracy Pictures 2009/November 2009/November 23 2009", + "/zzz Tracy Picture Partition/2009/November 2009/November 3 2009|/zzz Tracy Pictures 2009/November 2009/November 3 2009", + "/zzz Tracy Picture Partition/2009/November 2009/November 4 2009|/zzz Tracy Pictures 2009/November 2009/November 4 2009", + "/zzz Tracy Picture Partition/2009/November 2009/November 5 2009|/zzz Tracy Pictures 2009/November 2009/November 5 2009", + "/zzz Tracy Picture Partition/2009/November 2009/November 7 2009|/zzz Tracy Pictures 2009/November 2009/November 7 2009", + "/zzz Tracy Picture Partition/2009/October 2009/October 1 2009|/zzz Tracy Pictures 2009/October 2009/October 1 2009", + "/zzz Tracy Picture Partition/2009/October 2009/October 12 2009|/zzz Tracy Pictures 2009/October 2009/October 12 2009", + "/zzz Tracy Picture Partition/2009/October 2009/October 2 2009|/zzz Tracy Pictures 2009/October 2009/October 2 2009", + "/zzz Tracy Picture Partition/2009/October 2009/October 21 2009|/zzz Tracy Pictures 2009/October 2009/October 21 2009", + "/zzz Tracy Picture Partition/2009/October 2009/October 22 2009|/zzz Tracy Pictures 2009/October 2009/October 22 2009", + "/zzz Tracy Picture Partition/2009/October 2009/October 23 2009|/zzz Tracy Pictures 2009/October 2009/October 23 2009", + "/zzz Tracy Picture Partition/2009/October 2009/October 31 2009|/zzz Tracy Pictures 2009/October 2009/October 31 2009", + "/zzz Tracy Picture Partition/2009/October 2009/October 4 2009|/zzz Tracy Pictures 2009/October 2009/October 4 2009", + "/zzz Tracy Picture Partition/2009/October 2009/October 5 2009|/zzz Tracy Pictures 2009/October 2009/October 5 2009", + "/zzz Tracy Picture Partition/2009/October 2009/October 8 2009|/zzz Tracy Pictures 2009/October 2009/October 8 2009", + "/zzz Tracy Picture Partition/2009/October 2009|/zzz Tracy Pictures 2009/October 2009", + "/zzz Tracy Picture Partition/2009/September 2009/September 14 2009|/zzz Tracy Pictures 2009/September 2009/September 14 2009", + "/zzz Tracy Picture Partition/2009/September 2009/September 18 2009|/zzz Tracy Pictures 2009/September 2009/September 18 2009", + "/zzz Tracy Picture Partition/2009/September 2009/September 19 2009|/zzz Tracy Pictures 2009/September 2009/September 19 2009", + "/zzz Tracy Picture Partition/2009/September 2009/September 20 2009|/zzz Tracy Pictures 2009/September 2009/September 20 2009", + "/zzz Tracy Picture Partition/2009/September 2009/September 23 2009|/zzz Tracy Pictures 2009/September 2009/September 23 2009", + "/zzz Tracy Picture Partition/2009/September 2009/September 24 2009|/zzz Tracy Pictures 2009/September 2009/September 24 2009", + "/zzz Tracy Picture Partition/2009/September 2009/September 26 2009|/zzz Tracy Pictures 2009/September 2009/September 26 2009", + "/zzz Tracy Picture Partition/2009/September 2009/September 29 2009|/zzz Tracy Pictures 2009/September 2009/September 29 2009", + "/zzz Tracy Picture Partition/2009/September 2009|/zzz Tracy Pictures 2009/September 2009", + "/zzz Tracy Picture Partition/2010/April 24 2010/April 2 2010|/zzz Tracy Pictures 2010/April 24 2010/April 2 2010", + "/zzz Tracy Picture Partition/2010/April 24 2010/April 24 2010|/zzz Tracy Pictures 2010/April 24 2010/April 24 2010", + "/zzz Tracy Picture Partition/2010/April 24 2010/April 4 2010|/zzz Tracy Pictures 2010/April 24 2010/April 4 2010", + "/zzz Tracy Picture Partition/2010/April 24 2010/April 5 2010|/zzz Tracy Pictures 2010/April 24 2010/April 5 2010", + "/zzz Tracy Picture Partition/2010/April 24 2010/April 7 2010|/zzz Tracy Pictures 2010/April 24 2010/April 7 2010", + "/zzz Tracy Picture Partition/2010/April 24 2010/April 8 2010|/zzz Tracy Pictures 2010/April 24 2010/April 8 2010", + "/zzz Tracy Picture Partition/2010/August 2010/August 12 2010|/zzz Tracy Pictures 2010/August 2010/August 12 2010", + "/zzz Tracy Picture Partition/2010/August 2010/August 14 2010|/zzz Tracy Pictures 2010/August 2010/August 14 2010", + "/zzz Tracy Picture Partition/2010/August 2010/August 15 2010|/zzz Tracy Pictures 2010/August 2010/August 15 2010", + "/zzz Tracy Picture Partition/2010/August 2010/August 7 2010|/zzz Tracy Pictures 2010/August 2010/August 7 2010", + "/zzz Tracy Picture Partition/2010/February 2010/February 13 2010|/zzz Tracy Pictures 2010/February 2010/February 13 2010", + "/zzz Tracy Picture Partition/2010/February 2010/February 14 2010|/zzz Tracy Pictures 2010/February 2010/February 14 2010", + "/zzz Tracy Picture Partition/2010/February 2010/February 19 2010|/zzz Tracy Pictures 2010/February 2010/February 19 2010", + "/zzz Tracy Picture Partition/2010/February 2010/February 28 2010|/zzz Tracy Pictures 2010/February 2010/February 28 2010", + "/zzz Tracy Picture Partition/2010/February 2010/February 4 2010|/zzz Tracy Pictures 2010/February 2010/February 4 2010", + "/zzz Tracy Picture Partition/2010/February 2010/February 9 2010|/zzz Tracy Pictures 2010/February 2010/February 9 2010", + "/zzz Tracy Picture Partition/2010/Febuary 2010/Febuary 13 2010|/zzz Tracy Pictures 2010/Febuary 2010/Febuary 13 2010", + "/zzz Tracy Picture Partition/2010/Febuary 2010/Febuary 14 2010|/zzz Tracy Pictures 2010/Febuary 2010/Febuary 14 2010", + "/zzz Tracy Picture Partition/2010/Febuary 2010/Febuary 19 2010|/zzz Tracy Pictures 2010/Febuary 2010/Febuary 19 2010", + "/zzz Tracy Picture Partition/2010/Febuary 2010/Febuary 28 2010|/zzz Tracy Pictures 2010/Febuary 2010/Febuary 28 2010", + "/zzz Tracy Picture Partition/2010/Febuary 2010/Febuary 4 2010|/zzz Tracy Pictures 2010/Febuary 2010/Febuary 4 2010", + "/zzz Tracy Picture Partition/2010/Febuary 2010/Febuary 9 2010|/zzz Tracy Pictures 2010/Febuary 2010/Febuary 9 2010", + "/zzz Tracy Picture Partition/2010/January 2010/January 1 2010|/zzz Tracy Pictures 2010/January 2010/January 1 2010", + "/zzz Tracy Picture Partition/2010/January 2010/January 11 2010|/zzz Tracy Pictures 2010/January 2010/January 11 2010", + "/zzz Tracy Picture Partition/2010/January 2010/January 16 2010|/zzz Tracy Pictures 2010/January 2010/January 16 2010", + "/zzz Tracy Picture Partition/2010/January 2010/January 17 2010|/zzz Tracy Pictures 2010/January 2010/January 17 2010", + "/zzz Tracy Picture Partition/2010/January 2010/January 24 2010|/zzz Tracy Pictures 2010/January 2010/January 24 2010", + "/zzz Tracy Picture Partition/2010/January 2010/January 31 2010|/zzz Tracy Pictures 2010/January 2010/January 31 2010", + "/zzz Tracy Picture Partition/2010/January 2010/January 4 2010|/zzz Tracy Pictures 2010/January 2010/January 4 2010", + "/zzz Tracy Picture Partition/2010/July 29 2010|/zzz Tracy Pictures 2010/July 29 2010", + "/zzz Tracy Picture Partition/2010/March 2010/March 1 2010|/zzz Tracy Pictures 2010/March 2010/March 1 2010", + "/zzz Tracy Picture Partition/2010/March 2010/March 11 2010|/zzz Tracy Pictures 2010/March 2010/March 11 2010", + "/zzz Tracy Picture Partition/2010/March 2010/March 23 2010|/zzz Tracy Pictures 2010/March 2010/March 23 2010", + "/zzz Tracy Picture Partition/2010/March 2010/March 3 2010|/zzz Tracy Pictures 2010/March 2010/March 3 2010", + "/zzz Tracy Picture Partition/2010/March 2010/March 4 2010|/zzz Tracy Pictures 2010/March 2010/March 4 2010", + "/zzz Tracy Picture Partition/2010/March 2010/March 5 2010|/zzz Tracy Pictures 2010/March 2010/March 5 2010", + "/zzz Tracy Picture Partition/2010/March 2010/March 9 2010|/zzz Tracy Pictures 2010/March 2010/March 9 2010", + "/zzz Tracy Picture Partition/2010/October 18 2010/October 18 2010|/zzz Tracy Pictures 2010/October 18 2010/October 18 2010", + "/zzz Tracy Picture Partition/2010/October 18 2010|/zzz Tracy Pictures 2010/October 18 2010", + "/zzz Tracy Picture Partition/2010|/zzz Tracy Pictures 2010", + "/zzz Tracy Picture Partition/2011/April 2011/April 17 2011|/zzz Tracy Pictures 2011/April 2011/April 17 2011", + "/zzz Tracy Picture Partition/2011/April 2011|/zzz Tracy Pictures 2011/April 2011", + "/zzz Tracy Picture Partition/2011/August 2011/August 10 2011|/zzz Tracy Pictures 2011/August 2011/August 10 2011", + "/zzz Tracy Picture Partition/2011/August 2011/August 19 2011|/zzz Tracy Pictures 2011/August 2011/August 19 2011", + "/zzz Tracy Picture Partition/2011/August 2011/August 31 2011|/zzz Tracy Pictures 2011/August 2011/August 31 2011", + "/zzz Tracy Picture Partition/2011/August 2011/August 5 2011|/zzz Tracy Pictures 2011/August 2011/August 5 2011", + "/zzz Tracy Picture Partition/2011/August 2011|/zzz Tracy Pictures 2011/August 2011", + "/zzz Tracy Picture Partition/2011/December 2011/December 16 2011|/zzz Tracy Pictures 2011/December 2011/December 16 2011", + "/zzz Tracy Picture Partition/2011/December 2011/December 22 2011|/zzz Tracy Pictures 2011/December 2011/December 22 2011", + "/zzz Tracy Picture Partition/2011/December 2011/December 24 2011|/zzz Tracy Pictures 2011/December 2011/December 24 2011", + "/zzz Tracy Picture Partition/2011/December 2011/December 25 2011|/zzz Tracy Pictures 2011/December 2011/December 25 2011", + "/zzz Tracy Picture Partition/2011/December 2011/December 4 2011|/zzz Tracy Pictures 2011/December 2011/December 4 2011", + "/zzz Tracy Picture Partition/2011/December 2011/December 8 2011|/zzz Tracy Pictures 2011/December 2011/December 8 2011", + "/zzz Tracy Picture Partition/2011/December 2011|/zzz Tracy Pictures 2011/December 2011", + "/zzz Tracy Picture Partition/2011/July 2011/July 1 2011|/zzz Tracy Pictures 2011/July 2011/July 1 2011", + "/zzz Tracy Picture Partition/2011/July 2011/July 11 2011|/zzz Tracy Pictures 2011/July 2011/July 11 2011", + "/zzz Tracy Picture Partition/2011/July 2011/July 14 2011|/zzz Tracy Pictures 2011/July 2011/July 14 2011", + "/zzz Tracy Picture Partition/2011/July 2011/July 2 2011|/zzz Tracy Pictures 2011/July 2011/July 2 2011", + "/zzz Tracy Picture Partition/2011/July 2011/July 20 2011|/zzz Tracy Pictures 2011/July 2011/July 20 2011", + "/zzz Tracy Picture Partition/2011/July 2011/July 25 2011|/zzz Tracy Pictures 2011/July 2011/July 25 2011", + "/zzz Tracy Picture Partition/2011/July 2011/July 3 2011|/zzz Tracy Pictures 2011/July 2011/July 3 2011", + "/zzz Tracy Picture Partition/2011/July 2011/July 31 2011|/zzz Tracy Pictures 2011/July 2011/July 31 2011", + "/zzz Tracy Picture Partition/2011/July 2011/July 4 2011|/zzz Tracy Pictures 2011/July 2011/July 4 2011", + "/zzz Tracy Picture Partition/2011/July 2011/July 5 2011|/zzz Tracy Pictures 2011/July 2011/July 5 2011", + "/zzz Tracy Picture Partition/2011/July 2011|/zzz Tracy Pictures 2011/July 2011", + "/zzz Tracy Picture Partition/2011/June 2011/June 28 2011|/zzz Tracy Pictures 2011/June 2011/June 28 2011", + "/zzz Tracy Picture Partition/2011/June 2011/June 29 2011|/zzz Tracy Pictures 2011/June 2011/June 29 2011", + "/zzz Tracy Picture Partition/2011/June 2011/June 30 2011|/zzz Tracy Pictures 2011/June 2011/June 30 2011", + "/zzz Tracy Picture Partition/2011/June 2011|/zzz Tracy Pictures 2011/June 2011", + "/zzz Tracy Picture Partition/2011/March 2011/March 13 2011|/zzz Tracy Pictures 2011/March 2011/March 13 2011", + "/zzz Tracy Picture Partition/2011/March 2011/March 14 2011|/zzz Tracy Pictures 2011/March 2011/March 14 2011", + "/zzz Tracy Picture Partition/2011/March 2011/March 28 2011|/zzz Tracy Pictures 2011/March 2011/March 28 2011", + "/zzz Tracy Picture Partition/2011/March 2011|/zzz Tracy Pictures 2011/March 2011", + "/zzz Tracy Picture Partition/2011/May 2011|/zzz Tracy Pictures 2011/May 2011", + "/zzz Tracy Picture Partition/2011/November 2011/November 1 2011|/zzz Tracy Pictures 2011/November 2011/November 1 2011", + "/zzz Tracy Picture Partition/2011/November 2011/November 12 2011|/zzz Tracy Pictures 2011/November 2011/November 12 2011", + "/zzz Tracy Picture Partition/2011/November 2011/November 13 2011|/zzz Tracy Pictures 2011/November 2011/November 13 2011", + "/zzz Tracy Picture Partition/2011/November 2011/November 19 2011|/zzz Tracy Pictures 2011/November 2011/November 19 2011", + "/zzz Tracy Picture Partition/2011/November 2011/November 21 2011|/zzz Tracy Pictures 2011/November 2011/November 21 2011", + "/zzz Tracy Picture Partition/2011/November 2011/November 24 2011|/zzz Tracy Pictures 2011/November 2011/November 24 2011", + "/zzz Tracy Picture Partition/2011/November 2011/November 9 2011|/zzz Tracy Pictures 2011/November 2011/November 9 2011", + "/zzz Tracy Picture Partition/2011/November 2011|/zzz Tracy Pictures 2011/November 2011", + "/zzz Tracy Picture Partition/2011/October 2011/October 12 2011|/zzz Tracy Pictures 2011/October 2011/October 12 2011", + "/zzz Tracy Picture Partition/2011/October 2011/October 29 2011|/zzz Tracy Pictures 2011/October 2011/October 29 2011", + "/zzz Tracy Picture Partition/2011/October 2011/October 3 2011|/zzz Tracy Pictures 2011/October 2011/October 3 2011", + "/zzz Tracy Picture Partition/2011/October 2011/OCtober 5 2011|/zzz Tracy Pictures 2011/October 2011/OCtober 5 2011", + "/zzz Tracy Picture Partition/2011/October 2011/October 6 2011|/zzz Tracy Pictures 2011/October 2011/October 6 2011", + "/zzz Tracy Picture Partition/2011/October 2011|/zzz Tracy Pictures 2011/October 2011", + "/zzz Tracy Picture Partition/2011/September 2011/September 13 2011|/zzz Tracy Pictures 2011/September 2011/September 13 2011", + "/zzz Tracy Picture Partition/2011/September 2011/September 18 2011|/zzz Tracy Pictures 2011/September 2011/September 18 2011", + "/zzz Tracy Picture Partition/2011/September 2011/September 2 2011|/zzz Tracy Pictures 2011/September 2011/September 2 2011", + "/zzz Tracy Picture Partition/2011/September 2011/September 22 2011|/zzz Tracy Pictures 2011/September 2011/September 22 2011", + "/zzz Tracy Picture Partition/2011/September 2011/September 25 2011|/zzz Tracy Pictures 2011/September 2011/September 25 2011", + "/zzz Tracy Picture Partition/2011/September 2011/September 29 2011|/zzz Tracy Pictures 2011/September 2011/September 29 2011", + "/zzz Tracy Picture Partition/2011/September 2011/September 7 2011|/zzz Tracy Pictures 2011/September 2011/September 7 2011", + "/zzz Tracy Picture Partition/2011/September 2011/September 9 2011|/zzz Tracy Pictures 2011/September 2011/September 9 2011", + "/zzz Tracy Picture Partition/2011/September 2011|/zzz Tracy Pictures 2011/September 2011", + "/zzz Tracy Picture Partition/2011|/zzz Tracy Pictures 2011", + "/zzz Tracy Picture Partition/2012/April 2012/April 17 2012|/zzz Tracy Pictures 2012/April 2012/April 17 2012", + "/zzz Tracy Picture Partition/2012/April 2012/April 18 2012|/zzz Tracy Pictures 2012/April 2012/April 18 2012", + "/zzz Tracy Picture Partition/2012/April 2012/April 3 2012|/zzz Tracy Pictures 2012/April 2012/April 3 2012", + "/zzz Tracy Picture Partition/2012/April 2012/April 7 2012|/zzz Tracy Pictures 2012/April 2012/April 7 2012", + "/zzz Tracy Picture Partition/2012/April 2012/April 9 2012|/zzz Tracy Pictures 2012/April 2012/April 9 2012", + "/zzz Tracy Picture Partition/2012/April 2012|/zzz Tracy Pictures 2012/April 2012", + "/zzz Tracy Picture Partition/2012/August 2012/August 1 2012|/zzz Tracy Pictures 2012/August 2012/August 1 2012", + "/zzz Tracy Picture Partition/2012/August 2012/August 24 2012|/zzz Tracy Pictures 2012/August 2012/August 24 2012", + "/zzz Tracy Picture Partition/2012/August 2012|/zzz Tracy Pictures 2012/August 2012", + "/zzz Tracy Picture Partition/2012/December 2012/December 1 2012|/zzz Tracy Pictures 2012/December 2012/December 1 2012", + "/zzz Tracy Picture Partition/2012/December 2012/December 11 2012|/zzz Tracy Pictures 2012/December 2012/December 11 2012", + "/zzz Tracy Picture Partition/2012/December 2012/December 15 2012|/zzz Tracy Pictures 2012/December 2012/December 15 2012", + "/zzz Tracy Picture Partition/2012/December 2012/December 16 2012|/zzz Tracy Pictures 2012/December 2012/December 16 2012", + "/zzz Tracy Picture Partition/2012/December 2012/December 18 2012|/zzz Tracy Pictures 2012/December 2012/December 18 2012", + "/zzz Tracy Picture Partition/2012/December 2012/December 2 2012|/zzz Tracy Pictures 2012/December 2012/December 2 2012", + "/zzz Tracy Picture Partition/2012/December 2012/December 24 2012|/zzz Tracy Pictures 2012/December 2012/December 24 2012", + "/zzz Tracy Picture Partition/2012/December 2012/December 25 2012|/zzz Tracy Pictures 2012/December 2012/December 25 2012", + "/zzz Tracy Picture Partition/2012/December 2012/December 7 2012|/zzz Tracy Pictures 2012/December 2012/December 7 2012", + "/zzz Tracy Picture Partition/2012/December 2012/December 8 2012|/zzz Tracy Pictures 2012/December 2012/December 8 2012", + "/zzz Tracy Picture Partition/2012/December 2012/December 9 2012|/zzz Tracy Pictures 2012/December 2012/December 9 2012", + "/zzz Tracy Picture Partition/2012/February 2012/February 16 2012|/zzz Tracy Pictures 2012/February 2012/February 16 2012", + "/zzz Tracy Picture Partition/2012/February 2012/February 20 2012|/zzz Tracy Pictures 2012/February 2012/February 20 2012", + "/zzz Tracy Picture Partition/2012/February 2012/Febuary 16 2012|/zzz Tracy Pictures 2012/February 2012/Febuary 16 2012", + "/zzz Tracy Picture Partition/2012/February 2012/Febuary 20 2012|/zzz Tracy Pictures 2012/February 2012/Febuary 20 2012", + "/zzz Tracy Picture Partition/2012/February 2012|/zzz Tracy Pictures 2012/February 2012", + "/zzz Tracy Picture Partition/2012/January 2012/January 20 2012|/zzz Tracy Pictures 2012/January 2012/January 20 2012", + "/zzz Tracy Picture Partition/2012/January 2012|/zzz Tracy Pictures 2012/January 2012", + "/zzz Tracy Picture Partition/2012/July 2012/July 12 2012|/zzz Tracy Pictures 2012/July 2012/July 12 2012", + "/zzz Tracy Picture Partition/2012/July 2012/July 21 2012|/zzz Tracy Pictures 2012/July 2012/July 21 2012", + "/zzz Tracy Picture Partition/2012/July 2012/July 26 2012|/zzz Tracy Pictures 2012/July 2012/July 26 2012", + "/zzz Tracy Picture Partition/2012/July 2012|/zzz Tracy Pictures 2012/July 2012", + "/zzz Tracy Picture Partition/2012/June 2012/June 17 2012|/zzz Tracy Pictures 2012/June 2012/June 17 2012", + "/zzz Tracy Picture Partition/2012/June 2012/June 18 2012|/zzz Tracy Pictures 2012/June 2012/June 18 2012", + "/zzz Tracy Picture Partition/2012/June 2012/June 2 2012|/zzz Tracy Pictures 2012/June 2012/June 2 2012", + "/zzz Tracy Picture Partition/2012/June 2012/June 26 2012|/zzz Tracy Pictures 2012/June 2012/June 26 2012", + "/zzz Tracy Picture Partition/2012/June 2012/June 6 2012|/zzz Tracy Pictures 2012/June 2012/June 6 2012", + "/zzz Tracy Picture Partition/2012/June 2012|/zzz Tracy Pictures 2012/June 2012", + "/zzz Tracy Picture Partition/2012/March 2012/March 14 2012|/zzz Tracy Pictures 2012/March 2012/March 14 2012", + "/zzz Tracy Picture Partition/2012/March 2012/March 17 2012|/zzz Tracy Pictures 2012/March 2012/March 17 2012", + "/zzz Tracy Picture Partition/2012/March 2012/March 20 2012|/zzz Tracy Pictures 2012/March 2012/March 20 2012", + "/zzz Tracy Picture Partition/2012/March 2012/March 30 2012|/zzz Tracy Pictures 2012/March 2012/March 30 2012", + "/zzz Tracy Picture Partition/2012/March 2012/March 6 2012|/zzz Tracy Pictures 2012/March 2012/March 6 2012", + "/zzz Tracy Picture Partition/2012/March 2012/March 8 2012|/zzz Tracy Pictures 2012/March 2012/March 8 2012", + "/zzz Tracy Picture Partition/2012/March 2012|/zzz Tracy Pictures 2012/March 2012", + "/zzz Tracy Picture Partition/2012/May 2012/May 11 2012|/zzz Tracy Pictures 2012/May 2012/May 11 2012", + "/zzz Tracy Picture Partition/2012/May 2012/May 12 2012|/zzz Tracy Pictures 2012/May 2012/May 12 2012", + "/zzz Tracy Picture Partition/2012/May 2012/May 15 2012|/zzz Tracy Pictures 2012/May 2012/May 15 2012", + "/zzz Tracy Picture Partition/2012/May 2012/May 17 2012|/zzz Tracy Pictures 2012/May 2012/May 17 2012", + "/zzz Tracy Picture Partition/2012/May 2012/May 18 2012|/zzz Tracy Pictures 2012/May 2012/May 18 2012", + "/zzz Tracy Picture Partition/2012/May 2012/May 21 2012|/zzz Tracy Pictures 2012/May 2012/May 21 2012", + "/zzz Tracy Picture Partition/2012/May 2012/May 22 2012|/zzz Tracy Pictures 2012/May 2012/May 22 2012", + "/zzz Tracy Picture Partition/2012/May 2012/May 24 2012|/zzz Tracy Pictures 2012/May 2012/May 24 2012", + "/zzz Tracy Picture Partition/2012/May 2012/May 26 2012|/zzz Tracy Pictures 2012/May 2012/May 26 2012", + "/zzz Tracy Picture Partition/2012/May 2012|/zzz Tracy Pictures 2012/May 2012", + "/zzz Tracy Picture Partition/2012/November 2012/November 15 2012|/zzz Tracy Pictures 2012/November 2012/November 15 2012", + "/zzz Tracy Picture Partition/2012/November 2012/November 17 2012|/zzz Tracy Pictures 2012/November 2012/November 17 2012", + "/zzz Tracy Picture Partition/2012/November 2012/November 24 2012|/zzz Tracy Pictures 2012/November 2012/November 24 2012", + "/zzz Tracy Picture Partition/2012/November 2012/November 25 2012|/zzz Tracy Pictures 2012/November 2012/November 25 2012", + "/zzz Tracy Picture Partition/2012/November 2012/November 28 2012|/zzz Tracy Pictures 2012/November 2012/November 28 2012", + "/zzz Tracy Picture Partition/2012/November 2012/November 3 2012|/zzz Tracy Pictures 2012/November 2012/November 3 2012", + "/zzz Tracy Picture Partition/2012/November 2012|/zzz Tracy Pictures 2012/November 2012", + "/zzz Tracy Picture Partition/2012/October 2012/October 17 2012|/zzz Tracy Pictures 2012/October 2012/October 17 2012", + "/zzz Tracy Picture Partition/2012/October 2012/October 24 2012|/zzz Tracy Pictures 2012/October 2012/October 24 2012", + "/zzz Tracy Picture Partition/2012/October 2012/October 27 2012|/zzz Tracy Pictures 2012/October 2012/October 27 2012", + "/zzz Tracy Picture Partition/2012/October 2012/October 28 2012|/zzz Tracy Pictures 2012/October 2012/October 28 2012", + "/zzz Tracy Picture Partition/2012/October 2012/October 30 2012|/zzz Tracy Pictures 2012/October 2012/October 30 2012", + "/zzz Tracy Picture Partition/2012/October 2012/October 31 2012|/zzz Tracy Pictures 2012/October 2012/October 31 2012", + "/zzz Tracy Picture Partition/2012/October 2012/October 7 2012|/zzz Tracy Pictures 2012/October 2012/October 7 2012", + "/zzz Tracy Picture Partition/2012/October 2012|/zzz Tracy Pictures 2012/October 2012", + "/zzz Tracy Picture Partition/2012/Sebtember 2012/September 11 2012|/zzz Tracy Pictures 2012/Sebtember 2012/September 11 2012", + "/zzz Tracy Picture Partition/2012/Sebtember 2012/September 12 2012|/zzz Tracy Pictures 2012/Sebtember 2012/September 12 2012", + "/zzz Tracy Picture Partition/2012/Sebtember 2012/September 16 2012|/zzz Tracy Pictures 2012/Sebtember 2012/September 16 2012", + "/zzz Tracy Picture Partition/2012/Sebtember 2012/September 19 2012|/zzz Tracy Pictures 2012/Sebtember 2012/September 19 2012", + "/zzz Tracy Picture Partition/2012/Sebtember 2012/September 28 2012|/zzz Tracy Pictures 2012/Sebtember 2012/September 28 2012", + "/zzz Tracy Picture Partition/2012/Sebtember 2012/September 29 2012|/zzz Tracy Pictures 2012/Sebtember 2012/September 29 2012", + "/zzz Tracy Picture Partition/2012/Sebtember 2012/September 30 2012|/zzz Tracy Pictures 2012/Sebtember 2012/September 30 2012", + "/zzz Tracy Picture Partition/2012/September 2012/September 11 2012|/zzz Tracy Pictures 2012/September 2012/September 11 2012", + "/zzz Tracy Picture Partition/2012/September 2012/September 12 2012|/zzz Tracy Pictures 2012/September 2012/September 12 2012", + "/zzz Tracy Picture Partition/2012/September 2012/September 16 2012|/zzz Tracy Pictures 2012/September 2012/September 16 2012", + "/zzz Tracy Picture Partition/2012/September 2012/September 19 2012|/zzz Tracy Pictures 2012/September 2012/September 19 2012", + "/zzz Tracy Picture Partition/2012/September 2012/September 28 2012|/zzz Tracy Pictures 2012/September 2012/September 28 2012", + "/zzz Tracy Picture Partition/2012/September 2012/September 29 2012|/zzz Tracy Pictures 2012/September 2012/September 29 2012", + "/zzz Tracy Picture Partition/2012/September 2012/September 30 2012|/zzz Tracy Pictures 2012/September 2012/September 30 2012", + "/zzz Tracy Picture Partition/2013 Jan-July/April 2013/April 11 2013|/zzz Tracy Pictures 2013/April 2013/April 11 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/April 2013/April 17 2013|/zzz Tracy Pictures 2013/April 2013/April 17 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/April 2013/April 19 2013|/zzz Tracy Pictures 2013/April 2013/April 19 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/April 2013/April 21 2013|/zzz Tracy Pictures 2013/April 2013/April 21 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/April 2013/April 25 2013|/zzz Tracy Pictures 2013/April 2013/April 25 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/April 2013/April 28 2013|/zzz Tracy Pictures 2013/April 2013/April 28 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/February 2013|/zzz Tracy Pictures 2013/February 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/February 2013/February 23 2013|/zzz Tracy Pictures 2013/February 2013/February 23 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/February 2013/February 24 2013|/zzz Tracy Pictures 2013/February 2013/February 24 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/February 2013/February 5 2013|/zzz Tracy Pictures 2013/February 2013/February 5 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/February 2013/February 7 2013|/zzz Tracy Pictures 2013/February 2013/February 7 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/February 2013/Febuary 23 2013|/zzz Tracy Pictures 2013/Febuary 2013/Febuary 23 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/February 2013/Febuary 24 2013|/zzz Tracy Pictures 2013/Febuary 2013/Febuary 24 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/February 2013/Febuary 5 2013|/zzz Tracy Pictures 2013/Febuary 2013/Febuary 5 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/February 2013/Febuary 7 2013|/zzz Tracy Pictures 2013/Febuary 2013/Febuary 7 2013", + "/zzz Tracy Picture Partition/2013 Jan-July|/zzz Tracy Pictures 2013/January 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/January 2013/January 20 2013|/zzz Tracy Pictures 2013/January 2013/January 20 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/January 2013/January 25 2013|/zzz Tracy Pictures 2013/January 2013/January 25 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/July 2013|/zzz Tracy Pictures 2013/July 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/July 2013/July 13 2013|/zzz Tracy Pictures 2013/July 2013/July 13 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/July 2013/July 14 2013|/zzz Tracy Pictures 2013/July 2013/July 14 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/July 2013/July 3 2013|/zzz Tracy Pictures 2013/July 2013/July 3 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/July 2013/July 6 2013|/zzz Tracy Pictures 2013/July 2013/July 6 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/June 2013|/zzz Tracy Pictures 2013/June 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/June 2013/June 1 2013|/zzz Tracy Pictures 2013/June 2013/June 1 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/June 2013/June 10 2013|/zzz Tracy Pictures 2013/June 2013/June 10 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/June 2013/June 15 2013|/zzz Tracy Pictures 2013/June 2013/June 15 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/June 2013/June 16 2013|/zzz Tracy Pictures 2013/June 2013/June 16 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/June 2013/June 18 2013|/zzz Tracy Pictures 2013/June 2013/June 18 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/June 2013/June 19 2013|/zzz Tracy Pictures 2013/June 2013/June 19 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/June 2013/June 26 2013|/zzz Tracy Pictures 2013/June 2013/June 26 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/June 2013/June 28 2013|/zzz Tracy Pictures 2013/June 2013/June 28 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/June 2013/June 3 2013|/zzz Tracy Pictures 2013/June 2013/June 3 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/June 2013/June 9 2013|/zzz Tracy Pictures 2013/June 2013/June 9 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/March 2013|/zzz Tracy Pictures 2013/March 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/March 2013/March 16 2013|/zzz Tracy Pictures 2013/March 2013/March 16 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/March 2013/March 19 2013|/zzz Tracy Pictures 2013/March 2013/March 19 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/March 2013/March 28 2013|/zzz Tracy Pictures 2013/March 2013/March 28 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/March 2013/March 30 2013|/zzz Tracy Pictures 2013/March 2013/March 30 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/March 2013/March 31 2013|/zzz Tracy Pictures 2013/March 2013/March 31 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/May 2013/May 1 2013|/zzz Tracy Pictures 2013/May 2013/May 1 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/May 2013/May 12 2013|/zzz Tracy Pictures 2013/May 2013/May 12 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/May 2013/May 21 2013|/zzz Tracy Pictures 2013/May 2013/May 21 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/May 2013/May 29 2013|/zzz Tracy Pictures 2013/May 2013/May 29 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/May 2013/May 30 2013|/zzz Tracy Pictures 2013/May 2013/May 30 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/May 2013/May 31 2013|/zzz Tracy Pictures 2013/May 2013/May 31 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/May 2013/May 8 2013|/zzz Tracy Pictures 2013/May 2013/May 8 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/May 2013/May 9 2014|/zzz Tracy Pictures 2013/May 2013/May 9 2014", + "/zzz Tracy Picture Partition/2013 July- Dec/August 2013/August 14 2013|/zzz Tracy Pictures 2013/August 2013/August 14 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/August 2013/August 18 2013|/zzz Tracy Pictures 2013/August 2013/August 18 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/August 2013/August 19 2013|/zzz Tracy Pictures 2013/August 2013/August 19 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/August 2013/August 2 2013|/zzz Tracy Pictures 2013/August 2013/August 2 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/December 2013|/zzz Tracy Pictures 2013/December 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/December 2013/December 10 2013|/zzz Tracy Pictures 2013/December 2013/December 10 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/December 2013/December 23 2013|/zzz Tracy Pictures 2013/December 2013/December 23 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/December 2013/December 24 2013|/zzz Tracy Pictures 2013/December 2013/December 24 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/December 2013/December 9 2013|/zzz Tracy Pictures 2013/December 2013/December 9 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/July 2013/July 3 2013|/zzz Tracy Pictures 2013/July 3 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/November 2013|/zzz Tracy Pictures 2013/November 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/November 2013/November 15 2013|/zzz Tracy Pictures 2013/November 2013/November 15 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/November 2013/November 16 2013|/zzz Tracy Pictures 2013/November 2013/November 16 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/November 2013/November 20 2013|/zzz Tracy Pictures 2013/November 2013/November 20 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/November 2013/November 22 2013|/zzz Tracy Pictures 2013/November 2013/November 22 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/November 2013/November 28 2013|/zzz Tracy Pictures 2013/November 2013/November 28 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/October 2013|/zzz Tracy Pictures 2013/October 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/October 2013/October 12 2013|/zzz Tracy Pictures 2013/October 2013/October 12 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/October 2013/October 2 2013|/zzz Tracy Pictures 2013/October 2013/October 2 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/October 2013/October 20 2013|/zzz Tracy Pictures 2013/October 2013/October 20 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/October 2013/October 3 2013|/zzz Tracy Pictures 2013/October 2013/October 3 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/October 2013/OCtober 31 2013|/zzz Tracy Pictures 2013/October 2013/OCtober 31 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/September 2013|/zzz Tracy Pictures 2013/September 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/September 2013/September 1 2013|/zzz Tracy Pictures 2013/September 2013/September 1 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/September 2013/September 18 2013|/zzz Tracy Pictures 2013/September 2013/September 18 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/September 2013/September 27 2013|/zzz Tracy Pictures 2013/September 2013/September 27 2013", + "/zzz Tracy Picture Partition/2014/April 2014/April 17 2014|/zzz Tracy Pictures 2014/April 2014/April 17 2014", + "/zzz Tracy Picture Partition/2014/April 2014/April 27 2014|/zzz Tracy Pictures 2014/April 2014/April 27 2014", + "/zzz Tracy Picture Partition/2014/April 2014/April 30 2014|/zzz Tracy Pictures 2014/April 2014/April 30 2014", + "/zzz Tracy Picture Partition/2014/April 2014/April 9 2014|/zzz Tracy Pictures 2014/April 2014/April 9 2014", + "/zzz Tracy Picture Partition/2014/April 2014|/zzz Tracy Pictures 2014/April 2014", + "/zzz Tracy Picture Partition/2014/December 2014/December 19 2014|/zzz Tracy Pictures 2014/December 2014/December 19 2014", + "/zzz Tracy Picture Partition/2014/December 2014/December 20 2014|/zzz Tracy Pictures 2014/December 2014/December 20 2014", + "/zzz Tracy Picture Partition/2014/December 2014/December 24 2014|/zzz Tracy Pictures 2014/December 2014/December 24 2014", + "/zzz Tracy Picture Partition/2014/December 2014/December 25 2014|/zzz Tracy Pictures 2014/December 2014/December 25 2014", + "/zzz Tracy Picture Partition/2014/February 2014/February 27 2014|/zzz Tracy Pictures 2014/February 2014/February 27 2014", + "/zzz Tracy Picture Partition/2014/February 2014/February 8 2014|/zzz Tracy Pictures 2014/February 2014/February 8 2014", + "/zzz Tracy Picture Partition/2014/February 2014|/zzz Tracy Pictures 2014/February 2014", + "/zzz Tracy Picture Partition/2014/Febuary 2014/Febuary 27 2014|/zzz Tracy Pictures 2014/Febuary 2014/Febuary 27 2014", + "/zzz Tracy Picture Partition/2014/Febuary 2014/Febuary 8 2014|/zzz Tracy Pictures 2014/Febuary 2014/Febuary 8 2014", + "/zzz Tracy Picture Partition/2014/Febuary 2014|/zzz Tracy Pictures 2014/Febuary 2014", + "/zzz Tracy Picture Partition/2014/January 2014/January 20 2014|/zzz Tracy Pictures 2014/January 2014/January 20 2014", + "/zzz Tracy Picture Partition/2014/January 2014/January 31 2014|/zzz Tracy Pictures 2014/January 2014/January 31 2014", + "/zzz Tracy Picture Partition/2014/January 2014/January 4 2014|/zzz Tracy Pictures 2014/January 2014/January 4 2014", + "/zzz Tracy Picture Partition/2014/January 2014|/zzz Tracy Pictures 2014/January 2014", + "/zzz Tracy Picture Partition/2014/July 2014/July 19 2014|/zzz Tracy Pictures 2014/July 2014/July 19 2014", + "/zzz Tracy Picture Partition/2014/July 2014|/zzz Tracy Pictures 2014/July 2014", + "/zzz Tracy Picture Partition/2014/June 2014/June 17 2014|/zzz Tracy Pictures 2014/June 2014/June 17 2014", + "/zzz Tracy Picture Partition/2014/June 2014/June 20 2014|/zzz Tracy Pictures 2014/June 2014/June 20 2014", + "/zzz Tracy Picture Partition/2014/June 2014/June 21 2014|/zzz Tracy Pictures 2014/June 2014/June 21 2014", + "/zzz Tracy Picture Partition/2014/June 2014|/zzz Tracy Pictures 2014/June 2014", + "/zzz Tracy Picture Partition/2014/March 2014|/zzz Tracy Pictures 2014/March 2014", + "/zzz Tracy Picture Partition/2014/May 2014/May 15 2014|/zzz Tracy Pictures 2014/May 2014/May 15 2014", + "/zzz Tracy Picture Partition/2014/May 2014/May 17 2014|/zzz Tracy Pictures 2014/May 2014/May 17 2014", + "/zzz Tracy Picture Partition/2014/May 2014/May 22 2014|/zzz Tracy Pictures 2014/May 2014/May 22 2014", + "/zzz Tracy Picture Partition/2014/May 2014/May 23 2014|/zzz Tracy Pictures 2014/May 2014/May 23 2014", + "/zzz Tracy Picture Partition/2014/May 2014/May 24 2014|/zzz Tracy Pictures 2014/May 2014/May 24 2014", + "/zzz Tracy Picture Partition/2014/May 2014/May 25 2014|/zzz Tracy Pictures 2014/May 2014/May 25 2014", + "/zzz Tracy Picture Partition/2014/May 2014/May 26 2014|/zzz Tracy Pictures 2014/May 2014/May 26 2014", + "/zzz Tracy Picture Partition/2014/May 2014/May 3 2012 j bday|/zzz Tracy Pictures 2014/May 2014/May 3 2012 j bday", + "/zzz Tracy Picture Partition/2014/May 2014/May 6 2014|/zzz Tracy Pictures 2014/May 2014/May 6 2014", + "/zzz Tracy Picture Partition/2014/May 2014/May 9 2014|/zzz Tracy Pictures 2014/May 2014/May 9 2014", + "/zzz Tracy Picture Partition/2014/November 2014/November 2 2014|/zzz Tracy Pictures 2014/November 2014/November 2 2014", + "/zzz Tracy Picture Partition/2014/November 2014/November 20 2014|/zzz Tracy Pictures 2014/November 2014/November 20 2014", + "/zzz Tracy Picture Partition/2014/November 2014/November 23 2014|/zzz Tracy Pictures 2014/November 2014/November 23 2014", + "/zzz Tracy Picture Partition/2014/November 2014/November 24 2014|/zzz Tracy Pictures 2014/November 2014/November 24 2014", + "/zzz Tracy Picture Partition/2014/November 2014/November 27 2014|/zzz Tracy Pictures 2014/November 2014/November 27 2014", + "/zzz Tracy Picture Partition/2014/November 2014/November 29 2014|/zzz Tracy Pictures 2014/November 2014/November 29 2014", + "/zzz Tracy Picture Partition/2014/November 2014/November 3 2014|/zzz Tracy Pictures 2014/November 2014/November 3 2014", + "/zzz Tracy Picture Partition/2014/November 2014|/zzz Tracy Pictures 2014/November 2014", + "/zzz Tracy Picture Partition/2014/October 2014/October 11 2014|/zzz Tracy Pictures 2014/October 2014/October 11 2014", + "/zzz Tracy Picture Partition/2014/October 2014/October 17 2014|/zzz Tracy Pictures 2014/October 2014/October 17 2014", + "/zzz Tracy Picture Partition/2014/October 2014/October 18 2014|/zzz Tracy Pictures 2014/October 2014/October 18 2014", + "/zzz Tracy Picture Partition/2014/October 2014/October 24 2014|/zzz Tracy Pictures 2014/October 2014/October 24 2014", + "/zzz Tracy Picture Partition/2014/October 2014/October 26 2014|/zzz Tracy Pictures 2014/October 2014/October 26 2014", + "/zzz Tracy Picture Partition/2014/October 2014/October 30 2014|/zzz Tracy Pictures 2014/October 2014/October 30 2014", + "/zzz Tracy Picture Partition/2014/October 2014/OCtober 31 2014|/zzz Tracy Pictures 2014/October 2014/OCtober 31 2014", + "/zzz Tracy Picture Partition/2014/October 2014/October 8 2014|/zzz Tracy Pictures 2014/October 2014/October 8 2014", + "/zzz Tracy Picture Partition/2014/October 2014|/zzz Tracy Pictures 2014/October 2014", + "/zzz Tracy Picture Partition/2014/September 2014/September 12 2014|/zzz Tracy Pictures 2014/September 2014/September 12 2014", + "/zzz Tracy Picture Partition/2014/September 2014/September 20 2014|/zzz Tracy Pictures 2014/September 2014/September 20 2014", + "/zzz Tracy Picture Partition/2014/September 2014|/zzz Tracy Pictures 2014/September 2014", + "/zzz Tracy Picture Partition/2015/Copied from user Tracy/2015-01-01|/zzz Tracy Pictures 2015/Copied from user Tracy/2015-01-01" + ], + "RenameC": [ + "/Chelsea 2012", + "/Chelsea 2013", + "/Logan Michael 2007/Back to the hospital", + "/Logan Michael 2007/Birthday", + "/Logan Michael 2007/Dec 07", + "/Logan Michael 2007/Nov 07", + "/Logan Michael 2007/Oct 07", + "/Logan Michael 2007/Sept 07", + "/Logan Michael 2008/April 08", + "/Logan Michael 2008/Aug 08", + "/Logan Michael 2008/Feb 08", + "/Logan Michael 2008/Jan 08", + "/Logan Michael 2008/July 08", + "/Logan Michael 2008/June 08", + "/Logan Michael 2008/March 08", + "/Logan Michael 2008/May 08", + "/Logan Michael 2008/Nov 08", + "/Logan Michael 2008/Oct 08", + "/Logan Michael 2008/Sept 08", + "/Logan Michael 2009/April 09", + "/Logan Michael 2009/Aug Sept 09", + "/Logan Michael 2009/Dec 09", + "/Logan Michael 2009/Jan 09", + "/Logan Michael 2009/July 09", + "/Logan Michael 2009/June 09", + "/Logan Michael 2009/March 09", + "/Logan Michael 2009/May 09", + "/Logan Michael 2009/Nov 09", + "/Logan Michael 2009/Oct 09", + "/Logan Michael 2010/Jan 10", + "/Logan Michael 2010/March 10", + "/Logan Michael 2010/Oct 2010", + "/zzz Tracy Pictures 2005/April 2005", + "/zzz Tracy Pictures 2005/August 2005/August 30 2005", + "/zzz Tracy Pictures 2005/August 2005/August 31 2005", + "/zzz Tracy Pictures 2005/December 2005", + "/zzz Tracy Pictures 2005/December 2005/December 16 2005", + "/zzz Tracy Pictures 2005/December 2005/December 17 2005", + "/zzz Tracy Pictures 2005/December 2005/December 18 2005", + "/zzz Tracy Pictures 2005/December 2005/December 20 2005", + "/zzz Tracy Pictures 2005/December 2005/December 23 2005", + "/zzz Tracy Pictures 2005/December 2005/December 26 2005", + "/zzz Tracy Pictures 2005/December 2005/December 27 2005", + "/zzz Tracy Pictures 2005/December 2005/December 9 2005", + "/zzz Tracy Pictures 2005/July 2005", + "/zzz Tracy Pictures 2005/July 2005/July 1 2005", + "/zzz Tracy Pictures 2005/July 2005/July 2 2005", + "/zzz Tracy Pictures 2005/July 2005/July 4 2005", + "/zzz Tracy Pictures 2005/June 2005/June 28 2005", + "/zzz Tracy Pictures 2005/June 2005/June 29 2005", + "/zzz Tracy Pictures 2005/June 2005/June 30 2005", + "/zzz Tracy Pictures 2005/March 2005", + "/zzz Tracy Pictures 2005/MAy 2005", + "/zzz Tracy Pictures 2005/November 2005", + "/zzz Tracy Pictures 2005/November 2005/November 13 2005", + "/zzz Tracy Pictures 2005/November 2005/November 16 2005", + "/zzz Tracy Pictures 2005/November 2005/November 18 2005", + "/zzz Tracy Pictures 2005/November 2005/November 20 2005", + "/zzz Tracy Pictures 2005/November 2005/November 23 2005", + "/zzz Tracy Pictures 2005/November 2005/November 24 2005", + "/zzz Tracy Pictures 2005/November 2005/November 28 2005", + "/zzz Tracy Pictures 2005/November 2005/November 30 2005", + "/zzz Tracy Pictures 2005/November 2005/November 4 2005", + "/zzz Tracy Pictures 2005/November 2005/November 5 2005", + "/zzz Tracy Pictures 2005/November 2005/November 6 2005", + "/zzz Tracy Pictures 2005/October 2005", + "/zzz Tracy Pictures 2005/October 2005/October 11 2005", + "/zzz Tracy Pictures 2005/October 2005/October 17 2005", + "/zzz Tracy Pictures 2005/October 2005/October 30 2005", + "/zzz Tracy Pictures 2005/October 2005/October 4 2005", + "/zzz Tracy Pictures 2005/October 2005/October 6 2005", + "/zzz Tracy Pictures 2005/September 2005", + "/zzz Tracy Pictures 2005/September 2005/September 10 2005", + "/zzz Tracy Pictures 2005/September 2005/September 2 2005", + "/zzz Tracy Pictures 2005/September 2005/September 20 2005", + "/zzz Tracy Pictures 2005/September 2005/September 25 2005", + "/zzz Tracy Pictures 2005/September 2005/September 26 2005", + "/zzz Tracy Pictures 2005/September 2005/September 28 2005", + "/zzz Tracy Pictures 2005/September 2005/September 3 2005", + "/zzz Tracy Pictures 2005/September 2005/September 4 2005", + "/zzz Tracy Pictures 2005/September 2005/September 5 2005", + "/zzz Tracy Pictures 2005/September 2005/September 6 2005", + "/zzz Tracy Pictures 2005/September 2005/September 7 2005", + "/zzz Tracy Pictures 2005/September 2005/September 8 2005", + "/zzz Tracy Pictures 2006/April 2006/April 12 2006", + "/zzz Tracy Pictures 2006/April 2006/April 14 2006", + "/zzz Tracy Pictures 2006/April 2006/April 16 2006", + "/zzz Tracy Pictures 2006/April 2006/April 17 2006", + "/zzz Tracy Pictures 2006/April 2006/April 18 2006", + "/zzz Tracy Pictures 2006/April 2006/April 19 2006", + "/zzz Tracy Pictures 2006/April 2006/April 20 2006", + "/zzz Tracy Pictures 2006/April 2006/April 21 2006", + "/zzz Tracy Pictures 2006/April 2006/April 23 2006", + "/zzz Tracy Pictures 2006/April 2006/April 24 2006", + "/zzz Tracy Pictures 2006/April 2006/April 25 2006", + "/zzz Tracy Pictures 2006/April 2006/April 3 2006", + "/zzz Tracy Pictures 2006/April 2006/April 6 2006", + "/zzz Tracy Pictures 2006/March 2006/March 27 2006", + "/zzz Tracy Pictures 2006/March 2006/March 28 2006", + "/zzz Tracy Pictures 2006/March 2006/March 29 2006", + "/zzz Tracy Pictures 2006/March 2006/March 30 2006", + "/zzz Tracy Pictures 2007/August 2007/August 10 2007", + "/zzz Tracy Pictures 2007/August 2007/August 6 2007", + "/zzz Tracy Pictures 2007/August 2007/August 7 2007", + "/zzz Tracy Pictures 2007/February 2007/February 10 2007", + "/zzz Tracy Pictures 2007/February 2007/February 13 2007", + "/zzz Tracy Pictures 2007/February 2007/February 15 2007", + "/zzz Tracy Pictures 2007/February 2007/February 16 2007", + "/zzz Tracy Pictures 2007/February 2007/February 19 2007", + "/zzz Tracy Pictures 2007/Febuary 2007/Febuary 10 2007", + "/zzz Tracy Pictures 2007/Febuary 2007/Febuary 13 2007", + "/zzz Tracy Pictures 2007/Febuary 2007/Febuary 15 2007", + "/zzz Tracy Pictures 2007/Febuary 2007/Febuary 16 2007", + "/zzz Tracy Pictures 2007/Febuary 2007/Febuary 19 2007", + "/zzz Tracy Pictures 2007/September 2007", + "/zzz Tracy Pictures 2007/September 2007/September 5 2007", + "/zzz Tracy Pictures 2008", + "/zzz Tracy Pictures 2009/December 2009/December 1 2009", + "/zzz Tracy Pictures 2009/December 2009/December 11 2009", + "/zzz Tracy Pictures 2009/December 2009/December 12 2009", + "/zzz Tracy Pictures 2009/December 2009/December 16 2009", + "/zzz Tracy Pictures 2009/December 2009/December 18 2009", + "/zzz Tracy Pictures 2009/December 2009/December 20 2009", + "/zzz Tracy Pictures 2009/December 2009/December 21 2009", + "/zzz Tracy Pictures 2009/December 2009/December 22 2009", + "/zzz Tracy Pictures 2009/December 2009/December 25 2009", + "/zzz Tracy Pictures 2009/December 2009/December 3 2009", + "/zzz Tracy Pictures 2009/December 2009/December 31 2009", + "/zzz Tracy Pictures 2009/February 2009", + "/zzz Tracy Pictures 2009/February 2009/February 1 2009", + "/zzz Tracy Pictures 2009/February 2009/February 18 2009", + "/zzz Tracy Pictures 2009/February 2009/February 2 2009", + "/zzz Tracy Pictures 2009/Febuary 2009", + "/zzz Tracy Pictures 2009/Febuary 2009/Febuary 1 2009", + "/zzz Tracy Pictures 2009/Febuary 2009/Febuary 18 2009", + "/zzz Tracy Pictures 2009/Febuary 2009/Febuary 2 2009", + "/zzz Tracy Pictures 2009/January 2009", + "/zzz Tracy Pictures 2009/January 2009/January 12 2009", + "/zzz Tracy Pictures 2009/January 2009/January 13 2009", + "/zzz Tracy Pictures 2009/January 2009/January 14 2009", + "/zzz Tracy Pictures 2009/January 2009/January 15 2009", + "/zzz Tracy Pictures 2009/January 2009/January 19 2009", + "/zzz Tracy Pictures 2009/January 2009/January 27 2009", + "/zzz Tracy Pictures 2009/January 2009/January 28 2009", + "/zzz Tracy Pictures 2009/January 2009/January 29 2009", + "/zzz Tracy Pictures 2009/January 2009/January 4 2009", + "/zzz Tracy Pictures 2009/January 2009/January 6 2009", + "/zzz Tracy Pictures 2009/January 2009/January 9 2009", + "/zzz Tracy Pictures 2009/November 2009/November 17 2009", + "/zzz Tracy Pictures 2009/November 2009/November 18 2009", + "/zzz Tracy Pictures 2009/November 2009/November 2 2009", + "/zzz Tracy Pictures 2009/November 2009/November 21 2009", + "/zzz Tracy Pictures 2009/November 2009/November 22 2009", + "/zzz Tracy Pictures 2009/November 2009/November 23 2009", + "/zzz Tracy Pictures 2009/November 2009/November 3 2009", + "/zzz Tracy Pictures 2009/November 2009/November 4 2009", + "/zzz Tracy Pictures 2009/November 2009/November 5 2009", + "/zzz Tracy Pictures 2009/November 2009/November 7 2009", + "/zzz Tracy Pictures 2009/October 2009", + "/zzz Tracy Pictures 2009/October 2009/October 1 2009", + "/zzz Tracy Pictures 2009/October 2009/October 12 2009", + "/zzz Tracy Pictures 2009/October 2009/October 2 2009", + "/zzz Tracy Pictures 2009/October 2009/October 21 2009", + "/zzz Tracy Pictures 2009/October 2009/October 22 2009", + "/zzz Tracy Pictures 2009/October 2009/October 23 2009", + "/zzz Tracy Pictures 2009/October 2009/October 31 2009", + "/zzz Tracy Pictures 2009/October 2009/October 4 2009", + "/zzz Tracy Pictures 2009/October 2009/October 5 2009", + "/zzz Tracy Pictures 2009/October 2009/October 8 2009", + "/zzz Tracy Pictures 2009/September 2009", + "/zzz Tracy Pictures 2009/September 2009/September 14 2009", + "/zzz Tracy Pictures 2009/September 2009/September 18 2009", + "/zzz Tracy Pictures 2009/September 2009/September 19 2009", + "/zzz Tracy Pictures 2009/September 2009/September 20 2009", + "/zzz Tracy Pictures 2009/September 2009/September 23 2009", + "/zzz Tracy Pictures 2009/September 2009/September 24 2009", + "/zzz Tracy Pictures 2009/September 2009/September 26 2009", + "/zzz Tracy Pictures 2009/September 2009/September 29 2009", + "/zzz Tracy Pictures 2010", + "/zzz Tracy Pictures 2010/April 24 2010/April 2 2010", + "/zzz Tracy Pictures 2010/April 24 2010/April 24 2010", + "/zzz Tracy Pictures 2010/April 24 2010/April 4 2010", + "/zzz Tracy Pictures 2010/April 24 2010/April 5 2010", + "/zzz Tracy Pictures 2010/April 24 2010/April 7 2010", + "/zzz Tracy Pictures 2010/April 24 2010/April 8 2010", + "/zzz Tracy Pictures 2010/August 2010/August 12 2010", + "/zzz Tracy Pictures 2010/August 2010/August 14 2010", + "/zzz Tracy Pictures 2010/August 2010/August 15 2010", + "/zzz Tracy Pictures 2010/August 2010/August 7 2010", + "/zzz Tracy Pictures 2010/February 2010/February 13 2010", + "/zzz Tracy Pictures 2010/February 2010/February 14 2010", + "/zzz Tracy Pictures 2010/February 2010/February 19 2010", + "/zzz Tracy Pictures 2010/February 2010/February 28 2010", + "/zzz Tracy Pictures 2010/February 2010/February 4 2010", + "/zzz Tracy Pictures 2010/February 2010/February 9 2010", + "/zzz Tracy Pictures 2010/Febuary 2010/Febuary 13 2010", + "/zzz Tracy Pictures 2010/Febuary 2010/Febuary 14 2010", + "/zzz Tracy Pictures 2010/Febuary 2010/Febuary 19 2010", + "/zzz Tracy Pictures 2010/Febuary 2010/Febuary 28 2010", + "/zzz Tracy Pictures 2010/Febuary 2010/Febuary 4 2010", + "/zzz Tracy Pictures 2010/Febuary 2010/Febuary 9 2010", + "/zzz Tracy Pictures 2010/January 2010/January 1 2010", + "/zzz Tracy Pictures 2010/January 2010/January 11 2010", + "/zzz Tracy Pictures 2010/January 2010/January 16 2010", + "/zzz Tracy Pictures 2010/January 2010/January 17 2010", + "/zzz Tracy Pictures 2010/January 2010/January 24 2010", + "/zzz Tracy Pictures 2010/January 2010/January 31 2010", + "/zzz Tracy Pictures 2010/January 2010/January 4 2010", + "/zzz Tracy Pictures 2010/July 29 2010", + "/zzz Tracy Pictures 2010/March 2010/March 1 2010", + "/zzz Tracy Pictures 2010/March 2010/March 11 2010", + "/zzz Tracy Pictures 2010/March 2010/March 23 2010", + "/zzz Tracy Pictures 2010/March 2010/March 3 2010", + "/zzz Tracy Pictures 2010/March 2010/March 4 2010", + "/zzz Tracy Pictures 2010/March 2010/March 5 2010", + "/zzz Tracy Pictures 2010/March 2010/March 9 2010", + "/zzz Tracy Pictures 2010/October 18 2010", + "/zzz Tracy Pictures 2010/October 18 2010/October 18 2010", + "/zzz Tracy Pictures 2011", + "/zzz Tracy Pictures 2011/April 2011", + "/zzz Tracy Pictures 2011/April 2011/April 17 2011", + "/zzz Tracy Pictures 2011/August 2011", + "/zzz Tracy Pictures 2011/August 2011/August 10 2011", + "/zzz Tracy Pictures 2011/August 2011/August 19 2011", + "/zzz Tracy Pictures 2011/August 2011/August 31 2011", + "/zzz Tracy Pictures 2011/August 2011/August 5 2011", + "/zzz Tracy Pictures 2011/December 2011", + "/zzz Tracy Pictures 2011/December 2011/December 16 2011", + "/zzz Tracy Pictures 2011/December 2011/December 22 2011", + "/zzz Tracy Pictures 2011/December 2011/December 24 2011", + "/zzz Tracy Pictures 2011/December 2011/December 25 2011", + "/zzz Tracy Pictures 2011/December 2011/December 4 2011", + "/zzz Tracy Pictures 2011/December 2011/December 8 2011", + "/zzz Tracy Pictures 2011/July 2011", + "/zzz Tracy Pictures 2011/July 2011/July 1 2011", + "/zzz Tracy Pictures 2011/July 2011/July 11 2011", + "/zzz Tracy Pictures 2011/July 2011/July 14 2011", + "/zzz Tracy Pictures 2012/February 2012", + "/zzz Tracy Pictures 2012/February 2012/February 16 2012", + "/zzz Tracy Pictures 2012/February 2012/February 20 2012", + "/zzz Tracy Pictures 2012/February 2012/Febuary 16 2012", + "/zzz Tracy Pictures 2012/February 2012/Febuary 20 2012", + "/zzz Tracy Pictures 2011/July 2011/July 2 2011", + "/zzz Tracy Pictures 2011/July 2011/July 20 2011", + "/zzz Tracy Pictures 2011/July 2011/July 25 2011", + "/zzz Tracy Pictures 2011/July 2011/July 3 2011", + "/zzz Tracy Pictures 2011/July 2011/July 31 2011", + "/zzz Tracy Pictures 2011/July 2011/July 4 2011", + "/zzz Tracy Pictures 2011/July 2011/July 5 2011", + "/zzz Tracy Pictures 2011/June 2011", + "/zzz Tracy Pictures 2011/June 2011/June 28 2011", + "/zzz Tracy Pictures 2011/June 2011/June 29 2011", + "/zzz Tracy Pictures 2011/June 2011/June 30 2011", + "/zzz Tracy Pictures 2011/March 2011", + "/zzz Tracy Pictures 2011/March 2011/March 13 2011", + "/zzz Tracy Pictures 2011/March 2011/March 14 2011", + "/zzz Tracy Pictures 2011/March 2011/March 28 2011", + "/zzz Tracy Pictures 2011/May 2011", + "/zzz Tracy Pictures 2011/November 2011", + "/zzz Tracy Pictures 2011/November 2011/November 1 2011", + "/zzz Tracy Pictures 2011/November 2011/November 12 2011", + "/zzz Tracy Pictures 2011/November 2011/November 13 2011", + "/zzz Tracy Pictures 2011/November 2011/November 19 2011", + "/zzz Tracy Pictures 2011/November 2011/November 21 2011", + "/zzz Tracy Pictures 2011/November 2011/November 24 2011", + "/zzz Tracy Pictures 2011/November 2011/November 9 2011", + "/zzz Tracy Pictures 2011/October 2011", + "/zzz Tracy Pictures 2011/October 2011/October 12 2011", + "/zzz Tracy Pictures 2011/October 2011/October 29 2011", + "/zzz Tracy Pictures 2011/October 2011/October 3 2011", + "/zzz Tracy Pictures 2011/October 2011/OCtober 5 2011", + "/zzz Tracy Pictures 2011/October 2011/October 6 2011", + "/zzz Tracy Pictures 2011/September 2011", + "/zzz Tracy Pictures 2011/September 2011/September 13 2011", + "/zzz Tracy Pictures 2011/September 2011/September 18 2011", + "/zzz Tracy Pictures 2011/September 2011/September 2 2011", + "/zzz Tracy Pictures 2011/September 2011/September 22 2011", + "/zzz Tracy Pictures 2011/September 2011/September 25 2011", + "/zzz Tracy Pictures 2011/September 2011/September 29 2011", + "/zzz Tracy Pictures 2011/September 2011/September 7 2011", + "/zzz Tracy Pictures 2011/September 2011/September 9 2011", + "/zzz Tracy Pictures 2012/April 2012", + "/zzz Tracy Pictures 2012/April 2012/April 17 2012", + "/zzz Tracy Pictures 2012/April 2012/April 18 2012", + "/zzz Tracy Pictures 2012/April 2012/April 3 2012", + "/zzz Tracy Pictures 2012/April 2012/April 7 2012", + "/zzz Tracy Pictures 2012/April 2012/April 9 2012", + "/zzz Tracy Pictures 2012/August 2012", + "/zzz Tracy Pictures 2012/August 2012/August 1 2012", + "/zzz Tracy Pictures 2012/August 2012/August 24 2012", + "/zzz Tracy Pictures 2012/December 2012/December 1 2012", + "/zzz Tracy Pictures 2012/December 2012/December 11 2012", + "/zzz Tracy Pictures 2012/December 2012/December 15 2012", + "/zzz Tracy Pictures 2012/December 2012/December 16 2012", + "/zzz Tracy Pictures 2012/December 2012/December 18 2012", + "/zzz Tracy Pictures 2012/December 2012/December 2 2012", + "/zzz Tracy Pictures 2012/December 2012/December 24 2012", + "/zzz Tracy Pictures 2012/December 2012/December 25 2012", + "/zzz Tracy Pictures 2012/December 2012/December 7 2012", + "/zzz Tracy Pictures 2012/December 2012/December 8 2012", + "/zzz Tracy Pictures 2012/December 2012/December 9 2012", + "/zzz Tracy Pictures 2012/Feburay 2012", + "/zzz Tracy Pictures 2012/Feburay 2012/February 16 2012", + "/zzz Tracy Pictures 2012/Feburay 2012/February 20 2012", + "/zzz Tracy Pictures 2012/Feburay 2012/Febuary 16 2012", + "/zzz Tracy Pictures 2012/Feburay 2012/Febuary 20 2012", + "/zzz Tracy Pictures 2012/January 2012", + "/zzz Tracy Pictures 2012/January 2012/January 20 2012", + "/zzz Tracy Pictures 2012/July 2012", + "/zzz Tracy Pictures 2012/July 2012/July 12 2012", + "/zzz Tracy Pictures 2012/July 2012/July 21 2012", + "/zzz Tracy Pictures 2012/July 2012/July 26 2012", + "/zzz Tracy Pictures 2012/June 2012", + "/zzz Tracy Pictures 2012/June 2012/June 17 2012", + "/zzz Tracy Pictures 2012/June 2012/June 18 2012", + "/zzz Tracy Pictures 2012/June 2012/June 2 2012", + "/zzz Tracy Pictures 2012/June 2012/June 26 2012", + "/zzz Tracy Pictures 2012/June 2012/June 6 2012", + "/zzz Tracy Pictures 2012/March 2012", + "/zzz Tracy Pictures 2012/March 2012/March 14 2012", + "/zzz Tracy Pictures 2012/March 2012/March 17 2012", + "/zzz Tracy Pictures 2012/March 2012/March 20 2012", + "/zzz Tracy Pictures 2012/March 2012/March 30 2012", + "/zzz Tracy Pictures 2012/March 2012/March 6 2012", + "/zzz Tracy Pictures 2012/March 2012/March 8 2012", + "/zzz Tracy Pictures 2012/May 2012", + "/zzz Tracy Pictures 2012/May 2012/May 11 2012", + "/zzz Tracy Pictures 2012/May 2012/May 12 2012", + "/zzz Tracy Pictures 2012/May 2012/May 15 2012", + "/zzz Tracy Pictures 2012/May 2012/May 17 2012", + "/zzz Tracy Pictures 2012/May 2012/May 18 2012", + "/zzz Tracy Pictures 2012/May 2012/May 21 2012", + "/zzz Tracy Pictures 2012/May 2012/May 22 2012", + "/zzz Tracy Pictures 2012/May 2012/May 24 2012", + "/zzz Tracy Pictures 2012/May 2012/May 26 2012", + "/zzz Tracy Pictures 2012/November 2012", + "/zzz Tracy Pictures 2012/November 2012/November 15 2012", + "/zzz Tracy Pictures 2012/November 2012/November 17 2012", + "/zzz Tracy Pictures 2012/November 2012/November 24 2012", + "/zzz Tracy Pictures 2012/November 2012/November 25 2012", + "/zzz Tracy Pictures 2012/November 2012/November 28 2012", + "/zzz Tracy Pictures 2012/November 2012/November 3 2012", + "/zzz Tracy Pictures 2012/October 2012", + "/zzz Tracy Pictures 2012/October 2012/October 17 2012", + "/zzz Tracy Pictures 2012/October 2012/October 24 2012", + "/zzz Tracy Pictures 2012/October 2012/October 27 2012", + "/zzz Tracy Pictures 2012/October 2012/October 28 2012", + "/zzz Tracy Pictures 2012/October 2012/October 30 2012", + "/zzz Tracy Pictures 2012/October 2012/October 31 2012", + "/zzz Tracy Pictures 2012/October 2012/October 7 2012", + "/zzz Tracy Pictures 2012/Sebtember 2012/September 11 2012", + "/zzz Tracy Pictures 2012/Sebtember 2012/September 12 2012", + "/zzz Tracy Pictures 2012/Sebtember 2012/September 16 2012", + "/zzz Tracy Pictures 2012/Sebtember 2012/September 19 2012", + "/zzz Tracy Pictures 2012/Sebtember 2012/September 28 2012", + "/zzz Tracy Pictures 2012/Sebtember 2012/September 29 2012", + "/zzz Tracy Pictures 2012/Sebtember 2012/September 30 2012", + "/zzz Tracy Pictures 2012/September 2012/September 11 2012", + "/zzz Tracy Pictures 2012/September 2012/September 12 2012", + "/zzz Tracy Pictures 2012/September 2012/September 16 2012", + "/zzz Tracy Pictures 2012/September 2012/September 19 2012", + "/zzz Tracy Pictures 2012/September 2012/September 28 2012", + "/zzz Tracy Pictures 2012/September 2012/September 29 2012", + "/zzz Tracy Pictures 2012/September 2012/September 30 2012", + "/zzz Tracy Pictures 2013/April 2013/April 11 2013", + "/zzz Tracy Pictures 2013/April 2013/April 17 2013", + "/zzz Tracy Pictures 2013/April 2013/April 19 2013", + "/zzz Tracy Pictures 2013/April 2013/April 21 2013", + "/zzz Tracy Pictures 2013/April 2013/April 25 2013", + "/zzz Tracy Pictures 2013/April 2013/April 28 2013", + "/zzz Tracy Pictures 2013/August 2013/August 14 2013", + "/zzz Tracy Pictures 2013/August 2013/August 18 2013", + "/zzz Tracy Pictures 2013/August 2013/August 19 2013", + "/zzz Tracy Pictures 2013/August 2013/August 2 2013", + "/zzz Tracy Pictures 2013/December 2013", + "/zzz Tracy Pictures 2013/December 2013/December 10 2013", + "/zzz Tracy Pictures 2013/December 2013/December 23 2013", + "/zzz Tracy Pictures 2013/December 2013/December 24 2013", + "/zzz Tracy Pictures 2013/December 2013/December 9 2013", + "/zzz Tracy Pictures 2013/February 2013", + "/zzz Tracy Pictures 2013/February 2013/February 23 2013", + "/zzz Tracy Pictures 2013/February 2013/February 24 2013", + "/zzz Tracy Pictures 2013/February 2013/February 5 2013", + "/zzz Tracy Pictures 2013/February 2013/February 7 2013", + "/zzz Tracy Pictures 2013/Febuary 2013", + "/zzz Tracy Pictures 2013/Febuary 2013/Febuary 23 2013", + "/zzz Tracy Pictures 2013/Febuary 2013/Febuary 24 2013", + "/zzz Tracy Pictures 2013/Febuary 2013/Febuary 5 2013", + "/zzz Tracy Pictures 2013/Febuary 2013/Febuary 7 2013", + "/zzz Tracy Pictures 2013/January 2013/January 20 2013", + "/zzz Tracy Pictures 2013/January 2013/January 25 2013", + "/zzz Tracy Pictures 2013/July 2013", + "/zzz Tracy Pictures 2013/July 2013/July 13 2013", + "/zzz Tracy Pictures 2013/July 2013/July 14 2013", + "/zzz Tracy Pictures 2013/July 2013/July 3 2013", + "/zzz Tracy Pictures 2013/July 2013/July 6 2013", + "/zzz Tracy Pictures 2013/July 3 2013", + "/zzz Tracy Pictures 2013/June 2013", + "/zzz Tracy Pictures 2013/June 2013/June 1 2013", + "/zzz Tracy Pictures 2013/June 2013/June 10 2013", + "/zzz Tracy Pictures 2013/June 2013/June 15 2013", + "/zzz Tracy Pictures 2013/June 2013/June 16 2013", + "/zzz Tracy Pictures 2013/June 2013/June 18 2013", + "/zzz Tracy Pictures 2013/June 2013/June 19 2013", + "/zzz Tracy Pictures 2013/June 2013/June 26 2013", + "/zzz Tracy Pictures 2013/June 2013/June 28 2013", + "/zzz Tracy Pictures 2013/June 2013/June 3 2013", + "/zzz Tracy Pictures 2013/June 2013/June 9 2013", + "/zzz Tracy Pictures 2013/March 2013", + "/zzz Tracy Pictures 2013/March 2013/March 16 2013", + "/zzz Tracy Pictures 2013/March 2013/March 19 2013", + "/zzz Tracy Pictures 2013/March 2013/March 28 2013", + "/zzz Tracy Pictures 2013/March 2013/March 30 2013", + "/zzz Tracy Pictures 2013/March 2013/March 31 2013", + "/zzz Tracy Pictures 2013/May 2013/May 1 2013", + "/zzz Tracy Pictures 2013/May 2013/May 12 2013", + "/zzz Tracy Pictures 2013/May 2013/May 21 2013", + "/zzz Tracy Pictures 2013/May 2013/May 29 2013", + "/zzz Tracy Pictures 2013/May 2013/May 30 2013", + "/zzz Tracy Pictures 2013/May 2013/May 31 2013", + "/zzz Tracy Pictures 2013/May 2013/May 8 2013", + "/zzz Tracy Pictures 2013/May 2013/May 9 2014", + "/zzz Tracy Pictures 2013/November 2013", + "/zzz Tracy Pictures 2013/November 2013/November 15 2013", + "/zzz Tracy Pictures 2013/November 2013/November 16 2013", + "/zzz Tracy Pictures 2013/November 2013/November 20 2013", + "/zzz Tracy Pictures 2013/November 2013/November 22 2013", + "/zzz Tracy Pictures 2013/November 2013/November 28 2013", + "/zzz Tracy Pictures 2013/October 2013", + "/zzz Tracy Pictures 2013/October 2013/October 12 2013", + "/zzz Tracy Pictures 2013/October 2013/October 2 2013", + "/zzz Tracy Pictures 2013/October 2013/October 20 2013", + "/zzz Tracy Pictures 2013/October 2013/October 3 2013", + "/zzz Tracy Pictures 2013/October 2013/OCtober 31 2013", + "/zzz Tracy Pictures 2013/September 2013", + "/zzz Tracy Pictures 2013/September 2013/September 1 2013", + "/zzz Tracy Pictures 2013/September 2013/September 18 2013", + "/zzz Tracy Pictures 2013/September 2013/September 27 2013", + "/zzz Tracy Pictures 2014/April 2014", + "/zzz Tracy Pictures 2014/April 2014/April 17 2014", + "/zzz Tracy Pictures 2014/April 2014/April 27 2014", + "/zzz Tracy Pictures 2014/April 2014/April 30 2014", + "/zzz Tracy Pictures 2014/April 2014/April 9 2014", + "/zzz Tracy Pictures 2014/December 2014/December 19 2014", + "/zzz Tracy Pictures 2014/December 2014/December 20 2014", + "/zzz Tracy Pictures 2014/December 2014/December 24 2014", + "/zzz Tracy Pictures 2014/December 2014/December 25 2014", + "/zzz Tracy Pictures 2014/February 2014", + "/zzz Tracy Pictures 2014/February 2014/February 27 2014", + "/zzz Tracy Pictures 2014/February 2014/February 8 2014", + "/zzz Tracy Pictures 2014/Febuary 2014", + "/zzz Tracy Pictures 2014/Febuary 2014/Febuary 27 2014", + "/zzz Tracy Pictures 2014/Febuary 2014/Febuary 8 2014", + "/zzz Tracy Pictures 2014/January 2014", + "/zzz Tracy Pictures 2014/January 2014/January 20 2014", + "/zzz Tracy Pictures 2014/January 2014/January 31 2014", + "/zzz Tracy Pictures 2014/January 2014/January 4 2014", + "/zzz Tracy Pictures 2014/July 2014", + "/zzz Tracy Pictures 2014/July 2014/July 19 2014", + "/zzz Tracy Pictures 2014/June 2014", + "/zzz Tracy Pictures 2014/June 2014/June 17 2014", + "/zzz Tracy Pictures 2014/June 2014/June 20 2014", + "/zzz Tracy Pictures 2014/June 2014/June 21 2014", + "/zzz Tracy Pictures 2014/March 2014", + "/zzz Tracy Pictures 2014/May 2014/May 15 2014", + "/zzz Tracy Pictures 2014/May 2014/May 17 2014", + "/zzz Tracy Pictures 2014/May 2014/May 22 2014", + "/zzz Tracy Pictures 2014/May 2014/May 23 2014", + "/zzz Tracy Pictures 2014/May 2014/May 24 2014", + "/zzz Tracy Pictures 2014/May 2014/May 25 2014", + "/zzz Tracy Pictures 2014/May 2014/May 26 2014", + "/zzz Tracy Pictures 2014/May 2014/May 3 2012 j bday", + "/zzz Tracy Pictures 2014/May 2014/May 6 2014", + "/zzz Tracy Pictures 2014/May 2014/May 9 2014", + "/zzz Tracy Pictures 2014/November 2014", + "/zzz Tracy Pictures 2014/November 2014/November 2 2014", + "/zzz Tracy Pictures 2014/November 2014/November 20 2014", + "/zzz Tracy Pictures 2014/November 2014/November 23 2014", + "/zzz Tracy Pictures 2014/November 2014/November 24 2014", + "/zzz Tracy Pictures 2014/November 2014/November 27 2014", + "/zzz Tracy Pictures 2014/November 2014/November 29 2014", + "/zzz Tracy Pictures 2014/November 2014/November 3 2014", + "/zzz Tracy Pictures 2014/October 2014", + "/zzz Tracy Pictures 2014/October 2014/October 11 2014", + "/zzz Tracy Pictures 2014/October 2014/October 17 2014", + "/zzz Tracy Pictures 2014/October 2014/October 18 2014", + "/zzz Tracy Pictures 2014/October 2014/October 24 2014", + "/zzz Tracy Pictures 2014/October 2014/October 26 2014", + "/zzz Tracy Pictures 2014/October 2014/October 30 2014", + "/zzz Tracy Pictures 2014/October 2014/OCtober 31 2014", + "/zzz Tracy Pictures 2014/October 2014/October 8 2014", + "/zzz Tracy Pictures 2014/September 2014", + "/zzz Tracy Pictures 2014/September 2014/September 12 2014", + "/zzz Tracy Pictures 2014/September 2014/September 20 2014", + "/zzz Tracy Pictures 2015/Copied from user Tracy/2015-01-01" + ] + } + } +} \ No newline at end of file diff --git a/Compare/appsettings.json b/Compare/appsettings.json new file mode 100644 index 0000000..65beeea --- /dev/null +++ b/Compare/appsettings.json @@ -0,0 +1,1609 @@ +{ + "Company": "Mike Phares", + "Linux": {}, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Log4netProvider": "Debug", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "MaxDegreeOfParallelism": 12, + "Serilog": { + "Using": [ + "Serilog.Sinks.Console", + "Serilog.Sinks.File" + ], + "MinimumLevel": "Debug", + "WriteTo": [ + { + "Name": "Debug", + "Args": { + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}" + } + }, + { + "Name": "Console", + "Args": { + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "%workingDirectory% - Log/log-.txt", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}", + "rollingInterval": "Hour" + } + } + ], + "Enrich": [ + "FromLogContext", + "WithMachineName", + "WithThreadId" + ], + "Properties": { + "Application": "Sample" + } + }, + "WorkingDirectoryName": "PharesApps", + "Windows": { + "Configuration": { + "DateGroup": "2022-04-07", + "DiffPropertyDirectory": "", + "FileNameDirectorySeparator": ".Z.", + "ForcePropertyLastWriteTimeToCreationTime": false, + "MaxImagesInDirectoryForTopLevelFirstPass": 50, + "Pattern": "[^ABCDEFGHIJKLMNOPQRSTUVWXYZbcdfghjklmnpqrstvwxyz0-9]", + "PopulatePropertyId": true, + "PropertiesChangedForProperty": false, + "RootDirectory": "", + "WriteBitmapDataBytes": false, + "ManualChanges": [ + "I:/Images 2013-12-15 - 27,202 Files, 330 Folders - 26.7 GB", + "I:/Images 2018-05-12 - 32,394 Files, 879 Folders - 53.5 GB", + "I:/Images 2018-12-25 - 33,346 Files, 488 Folders - 58.4 GB", + "I:/Images 2019-06-08 - 34,627 Files, 498 Folders - 64.5 GB", + "I:/Images 2021-10-29 - 40,517 Files, 528 Folders - 79.3 GB", + "I:/Images 2021-10-29 - - GB", + "I:/Images 2019-06-08 - 000035 Files, 006 Folders - 28.8 MB", + "I:/Images 2018-12-25 - 000045 Files, 009 Folders - 56.1 MB", + "I:/Images 2018-05-12 - 09,029 Files, 589 Folders - 15.0 GB", + "I:/Images 2013-12-15 - 13,848 Files, 214 Folders - 12.9 GB", + "/Tracy Picture Partition/2013 July- Dec/September 2013/September 27 2013/DSC_0658.JPG", + "/Greer, AZ 2016/DSC_2182.JPG", + "March 2013", + "May 2011", + "Spring 2018", + "Summer 2011", + "Winter 2018", + "/zzz Patrick", + "Chelsea 2012", + "Chelsea 2013", + "Seattle 2003", + "Seattle 2010", + "Seattle 2011", + "Jason's 11th Birthday 2009|Blackberry (878).jpg|Photo-0245.jpg", + "Blackberry|. 2009|. 2010|. 2011", + "Phone pictures|. 2010|. 2011|. 2012|. 2013", + "/zzz Phares Slides/Slides 2015-06-10/Magazine 01" + ], + "IgnoreExtensions": [ + ".gif", + ".GIF" + ], + "PropertyContentCollectionFiles": [ + "/Images 2022-04-17 - fa60aa45ebb55fe3ee0ce4da8a64e40611e7d5ce - III - Results/A) Property/2022-04-07/[()]/637869381676042455.json", + "/Not-Copy-Copy/Images 2019-06-08 - 34a9240ac28b52da97428d7725153a80a757ee6b - Not-Copy-Copy - Results/A) Property/2022-04-07/[()]/637869733124119330.json", + "/Not-Copy-Copy/Images 2018-12-25 - 34a9240ac28b52da97428d7725153a80a757ee6b - Not-Copy-Copy - Results/A) Property/2022-04-07/[()]/637869734240700328.json", + "/Not-Copy-Copy/Images 2018-05-12 - b01d4763d8853b6d6057a3870b2723449726da75 - Not-Copy-Copy - Results/A) Property/2022-04-07/[()]/637869734970730630.json", + "/Not-Copy-Copy/Images 2013-12-15 - d02c8791fa0b130c0bce2d39ee684e50f7ee7a97 - Not-Copy-Copy - Results/A) Property/2022-04-07/[()]/637869743752078399.json", + "/Not-Copy-Copy - Delta/Amazon Drive - Results/A) Property/2022-04-07/[()]/637869744751177715.json", + "/Not-Copy-Copy - Delta/Blackberry - Results/A) Property/2022-04-07/[()]/637869745134124462.json" + ], + "ValidImageFormatExtensions": [ + ".bmp", + ".BMP", + ".gif", + ".GIF", + ".jpeg", + ".JPEG", + ".jpg", + ".JPG", + ".png", + ".PNG", + ".tiff", + ".TIFF" + ], + "ValidMetadataExtensions": [ + ".3gp", + ".3GP", + ".amr", + ".AMR", + ".avi", + ".AVI", + ".bmp", + ".BMP", + ".gif", + ".GIF", + ".ico", + ".ICO", + ".jpeg", + ".JPEG", + ".jpg", + ".JPG", + ".m4v", + ".M4V", + ".mov", + ".MOV", + ".mp4", + ".MP4", + ".mta", + ".MTA", + ".png", + ".PNG", + ".tiff", + ".TIFF" + ], + "VerifyToSeason": [ + ". 2000", + ". 2001", + ". 2002", + ". 2003", + ". 2004", + ". 2005", + ". 2006", + ". 2007", + ". 2008", + ". 2009", + ". 2010", + ". 2011", + ". 2012", + ". 2013", + ". 2014", + ". 2015", + ". 2016", + ". 2017", + ". 2018", + ". 2019", + ". 2020", + ". 2021", + ". 2022", + ". 2023", + ". 2024", + ". 2025", + ". 2026", + ". 2027", + ". 2028", + ". 2029", + "=2000.0 Winter", + "=2002.1 Spring", + "=2002.4 Winter", + "=2003.0 Winter", + "=2003.1 Spring", + "=2003.3 Fall", + "=2003.4 Winter", + "=2004.0 Winter", + "=2005.1 Spring", + "=2005.2 Summer", + "=2005.3 Fall", + "=2005.4 Winter", + "=2006.0 Winter", + "=2006.1 Spring", + "=2006.3 Fall", + "=2007.0 Winter", + "=2007.2 Summer Logan Michael", + "=2007.2 Summer", + "=2007.3 Fall Logan Michael", + "=2007.4 Winter Logan Michael", + "=2008.0 Winter Logan Michael", + "=2008.1 Spring Logan Michael", + "=2008.2 Summer Logan Michael", + "=2008.2 Summer", + "=2008.3 Fall Logan Michael", + "=2009.0 Winter Logan Michael", + "=2009.0 Winter", + "=2009.1 Spring Logan Michael", + "=2009.1 Spring", + "=2009.2 Summer Logan Michael", + "=2009.2 Summer", + "=2009.3 Fall Logan Michael", + "=2009.3 Fall", + "=2009.4 Winter Logan Michael", + "=2009.4 Winter", + "=2010.0 Winter Logan Michael", + "=2010.0 Winter", + "=2010.1 Spring Logan Michael", + "=2010.1 Spring", + "=2010.2 Summer", + "=2010.3 Fall Logan Michael", + "=2010.3 Fall", + "=2010.4 Winter", + "=2011.0 Winter", + "=2011.1 Spring", + "=2011.2 Summer", + "=2011.3 Fall", + "=2011.4 Winter", + "=2012.0 Winter Chelsea 2012", + "=2012.0 Winter Chelsea", + "=2012.0 Winter", + "=2012.1 Spring Chelsea", + "=2012.1 Spring", + "=2012.2 Summer Chelsea", + "=2012.2 Summer", + "=2012.3 Fall Chelsea", + "=2012.3 Fall", + "=2012.4 Winter Chelsea", + "=2012.4 Winter", + "=2013.0 Winter Chelsea 2013", + "=2013.0 Winter Chelsea", + "=2013.0 Winter", + "=2013.1 Spring", + "=2013.2 Summer Chelsea", + "=2013.2 Summer", + "=2013.3 Fall Chelsea", + "=2013.3 Fall", + "=2013.4 Winter", + "=2014.0 Winter", + "=2014.1 Spring", + "=2014.2 Summer", + "=2014.3 Fall", + "=2014.4 Winter", + "=2015.0 Winter", + "=2015.1 Spring", + "=2015.2 Summer", + "=2015.3 Fall", + "=2015.4 Winter", + "=2016.0 Winter", + "=2016.1 Spring", + "=2016.2 Summer", + "=2016.3 Fall", + "=2016.4 Winter", + "=2017.1 Spring", + "=2017.2 Summer", + "=2017.3 Fall", + "=2017.4 Winter", + "=2018.0 Winter", + "=2018.1 Spring", + "=2018.3 Fall", + "=2018.4 Winter", + "=2019.0 Winter", + "=2019.1 Spring", + "=2019.2 Summer", + "=2019.3 Fall", + "=2019.4 Winter", + "=2020.0 Winter", + "=2020.1 Spring", + "=2020.2 Summer", + "=2020.3 Fall", + "=2020.4 Winter", + "=2021.1 Spring", + "=2021.2 Summer", + "=2021.3 Fall", + "=2021.4 Winter", + "=2022.0 Winter", + "=2022.1 Spring", + "Anthem 2015", + "April 2010", + "April 2013", + "December 2006", + "December 2010", + "Fall 2005", + "Fall 2015", + "Fall 2016", + "Fall 2017", + "Fall 2018", + "Fall 2019", + "Fall 2020", + "Fall 2021", + "February 2010", + "January 2015", + "July 2010", + "June 2010", + "Kids 2005", + "March 2013", + "May 2010", + "May 2011", + "May 2013", + "October 2005", + "October 2014", + "Spring 2013", + "Spring 2014", + "Spring 2016", + "Spring 2018", + "Spring 2019", + "Spring 2020", + "Summer 2011", + "Summer 2012", + "Summer 2013", + "Summer 2014", + "Summer 2015", + "Summer 2016", + "Summer 2017", + "Summer 2018", + "Summer 2020", + "Summer 2021", + "Winter 2015", + "Winter 2016", + "Winter 2017", + "Winter 2018", + "Winter 2019-2020", + "Winter 2020", + "zzz =2005.0 Winter Tracy Pictures", + "zzz =2005.1 Spring Tracy Pictures", + "zzz =2005.2 Summer Tracy Pictures", + "zzz =2005.3 Fall Tracy Pictures", + "zzz =2005.4 Winter Tracy Pictures", + "zzz =2006.1 Spring Tracy Pictures", + "zzz =2007.0 Winter Tracy Pictures", + "zzz =2007.2 Summer Tracy Pictures", + "zzz =2008.0 Winter Tracy Pictures", + "zzz =2008.2 Summer Tracy Pictures", + "zzz =2009.0 Winter Tracy Pictures", + "zzz =2009.2 Summer Tracy Pictures", + "zzz =2009.3 Fall Tracy Pictures", + "zzz =2009.4 Winter Tracy Pictures", + "zzz =2010.0 Winter Tracy Pictures", + "zzz =2010.1 Spring Tracy Pictures", + "zzz =2010.2 Summer Tracy Pictures", + "zzz =2010.3 Fall Tracy Pictures", + "zzz =2011.0 Winter Tracy Pictures", + "zzz =2011.1 Spring Tracy Pictures", + "zzz =2011.2 Summer Tracy Pictures", + "zzz =2011.3 Fall Tracy Pictures", + "zzz =2011.4 Winter Tracy Pictures", + "zzz =2012.0 Winter Tracy Pictures", + "zzz =2012.1 Spring Tracy Pictures", + "zzz =2012.2 Summer Tracy Pictures", + "zzz =2012.3 Fall Tracy Pictures", + "zzz =2012.4 Winter Tracy Pictures", + "zzz =2013.0 Winter Tracy Pictures", + "zzz =2013.1 Spring Tracy Pictures", + "zzz =2013.2 Summer Tracy Pictures", + "zzz =2013.3 Fall Tracy Pictures", + "zzz =2013.4 Winter Tracy Pictures", + "zzz =2014.0 Winter Tracy Pictures", + "zzz =2014.1 Spring Tracy Pictures", + "zzz =2014.2 Summer Tracy Pictures", + "zzz =2014.3 Fall Tracy Pictures", + "zzz =2014.4 Winter Tracy Pictures", + "zzz =2015.0 Winter Tracy Pictures" + ], + "Spelling": [ + "Bday|Birthday", + "Childrens|Children's", + "Darrens|Darren's", + "Febuary|February", + "Feburay|February", + "Frist|First", + "Goolgle|Google", + "Kristys|Kristy's", + "Micael's|Michael's", + "Origanls|Originals", + "Partion|Partition", + "Patrict|Patrick", + "Sebtember|September", + "ב|zzz" + ], + "Rename": [ + "=2012.0 Winter Chelsea 2012|=2012.0 Winter Chelsea", + "=2013.0 Winter Chelsea 2013|=2013.0 Winter Chelsea", + "2004 4th of July|4th of July 2004", + "2006 4th of July|4th of July 2006", + "2007 4th of July|4th of July 2007", + "2009 4th of July|4th of July 2009", + "2011 April|. 2011", + "3757 W Whitman|3757Whitman|3757Whitman|3757 W Whitman 2017", + "All Pictures from Wedding Originals|AllPicturesFromWeddingOriginals|AllPicturesFromWeddingOriginals|All Pictures from Wedding Originals 2006", + "Anthem2015|. 2015", + "April 2010|. 2011", + "April's Wedding|April'sWedding|April'sWedding|April's Wedding 2010", + "Arturo|ART|ART|Arturo 2002", + "asdf|ASDF|ASDF|asdf", + "AZ 2015|. 2015", + "AZ 2016|. 2016", + "AZ 2018|. 2018", + "AZ2016|. 2016", + "Baby Shower 2012|BabyShower2012|BabyShower2012|Chelsea Baby Shower 2012", + "Barrick Wedding|BarrickWedding|BarrickWedding|Barrick Wedding 2015", + "Blackberry 2009|. 2009", + "Blackberry 2010|. 2010", + "Blackberry 2011|. 2011", + "Broncos Game|BroncosGame|BroncosGame|Broncos Game 2010", + "Broncos Gme|Broncos Game 2010", + "Camp Shaver 2009|CampShaver2009|CampShaver2009|Jason Camp Shaver 2009", + "Chelsea's 2nd Birthday|Chelsea's2ndBirthday|Chelsea's2ndBirthday|Chelsea's 2nd Birthday 2014", + "Chelsea's 5th Birthday|Chelsea's5thBirthday|Chelsea's5thBirthday|Chelsea's 5th Birthday 2017", + "Chelsea's 7th Birthday|Chelsea's7thBirthday|Chelsea's7thBirthday|Chelsea's 7th Birthday 2018", + "Cliffs.Tanner 2015|Cliffs Tanner 2015", + "Crystal's Wedding|Crystal'sWedding|Crystal'sWedding|Crystal's Wedding 2003", + "Danny's Wedding|Danny'sWedding|Danny'sWedding|Danny's Wedding 2009", + "Darren's Camera|Darren'sCamera|Darren'sCamera|Darren's Camera 2006", + "Door images 2019|DoorImages2019|DoorImages2019|Door Images 2019", + "Engagement day|EngagementDay|EngagementDay|Engagement Day 2005", + "Engagement dy|Engagement Day 2005", + "Family 2000|. 2000", + "Family 2002|. 2002", + "Family 2003|. 2003", + "Family 2009|. 2009", + "Family Pictures 2006|zzz Family Pictures 2006", + "Family Pictures 2007|zzz Family Pictures 2007", + "Family Pictures 2011|zzz Family Pictures 2011", + "Family Pictures 2013|zzz Family Pictures 2013", + "Fathers Day 2015 Jemez|FathersDay2015Jemez|FathersDay2015Jemez|Fathers Day In Jemez 2015", + "Girl Scouts|Mackenzie Girl Scouts 2006", + "Grad Mike|GradMike|GradMike|Graduation Mike 2003", + "Grandma's Quilt|zzz Scanned Grandma's Quilt", + "Grandpa Ortega's Birthday|GrandpaOrtega'sBirthday|GrandpaOrtega'sBirthday|Grandpa Ortega's Birthday 2010", + "Grandpa Phares Services|GrandpaPharesServices|GrandpaPharesServices|Grandpa Phares Services 2012", + "GrandPrix 2004|zzz GrandPrix 2004", + "GrandPrix|zzz GrandPrix 2004", + "Herman Family Reunion|HermanFamilyReunion|HermanFamilyReunion|Herman Family Reunion 2008", + "Huval Wedding|HuvalWedding|HuvalWedding|Huval Wedding 2009", + "Jason & Kenzie Birthday Party 2010|Jason's 12th & Mackenzie's 10th Birthday Party 2010", + "Jason & Zack @Cliffs|JasonZackCliffs|JasonZackCliffs|Jason & Zack At Cliffs 2007", + "Jason 10 Birthday 2008|Jason's 10th Birthday 2008", + "Jason 10 birthday|Jason10Birthday|Jason10Birthday|Jason's 10th Birthday 2008", + "Jason 10th birthday|Jason10Birthday|Jason10Birthday|Jason's 10th Birthday 2008", + "Jason 12th Birthday 2010|Jason's 12th Birthday 2010", + "Jason 12th birthday|Jason12Birthday|Jason12Birthday|Jason's 12th Birthday 2010", + "Jason 13th bday|Jason13Birthday|Jason13Birthday|Jason's 13th Birthday 2011", + "Jason 13th Birthday 2011|Jason's 13th Birthday 2011", + "Jason 14th Birthday 2012|Jason's 14th Birthday 2012", + "Jason 14th Birthday|Jason14thBirthday|Jason14thBirthday|Jason's 14th Birthday 2012", + "Jason 2nd grade first day|Jason2ndGradeFirstDay|Jason2ndGradeFirstDay|Jason 2nd Grade First Day 2005", + "Jason 7 Birthday 2005|Jason's 7th Birthday 2005", + "Jason 7 birthday|Jason7Birthday|Jason7Birthday|Jason's 7th Birthday 2005", + "Jason 8 Birthday 2006|Jason's 8th Birthday 2006", + "Jason 8 birthday|Jason8Birthday|Jason8Birthday|Jason's 8th Birthday 2006", + "Jason 9th Birthday 2007|Jason's 9th Birthday 2007", + "Jason 9th birthday|Jason9Birthday|Jason9Birthday|Jason's 9th Birthday 2007", + "Jason first day kindergarten|JasonFirstDayKindergarten|JasonFirstDayKindergarten|Jason First Day Kindergarten 2003", + "Jason's camera work|Jason'sCameraWork|Jason'sCameraWork|Jason's Camera Work 2003", + "Jason's Collar Bone|Jason'sCollarBone|Jason'sCollarBone|Jason's Collar Bone 2008", + "Jason's glasses|Jason'sGlasses|Jason'sGlasses|Jason's Glasses 2006", + "Jason's Guitar|Jason'sGuitar|Jason'sGuitar|Jason's Guitar 2008", + "Jason's Teeth|Jason'sTeeth|Jason'sTeeth|Jason's Teeth 2004", + "Jason&Zack @Cliffs|Jason & Zack At Cliffs 2007", + "Jemez 9-08|Jemez08|Jemez08|Jemez 2008", + "Jemez 9-09|Jemez09|Jemez09|Jemez 2009", + "Jeremiah's Birthday|Jeremiah'sBirthday|Jeremiah'sBirthday|Jeremiah's Birthday 2008", + "Jeremiah's Christmas|Jeremiah'sChristmas|Jeremiah'sChristmas|Jeremiah's Christmas 2008", + "Johnny Graduation|JohnnyGraduation|JohnnyGraduation|Johnny Graduation 2007", + "Johnny's award|Johnny'sAward|Johnny'sAward|Johnny's Award 2007", + "Johnny's Hair|Johnny'sHair2008|Johnny'sHair2008|Johnny's Hair 2008", + "Johnny's Race|Johnny'sRace|Johnny'sRace|Johnny's Race 2006", + "Kids PJ Pants|KidsPJPants|KidsPJPants|Kids PJ Pants 2006", + "Kids School Pictures|KidsSchoolPictures|KidsSchoolPictures|Kids School Pictures 2004", + "Kids|KDS|KDS|Kids 2005", + "Kristy Parents Wedding|KristyParentsWedding|KristyParentsWedding|Kristy Parents Wedding 2005", + "Kristy|KRS|KRS|Kristy 2002", + "LAHS Reunion|LAHSReunion|LAHSReunion|LAHS Reunion 2014", + "Logan 5th Birthday 2012|Logan's 5th Birthday 2012", + "Logan 5th Birthday|Logan5thBirthday|Logan5thBirthday|Logan's 5th Birthday 2012", + "Logan Preschool Graduation|LoganPreschoolGraduation|LoganPreschoolGraduation|Logan Preschool Graduation 2013", + "Logan Valentines Party|LoganValentinesParty|LoganValentinesParty|Logan Valentines Party 2013", + "Logan Vegas|LoganVegas|LoganVegas|Logan Vegas 2016", + "Logan's 10th Birthday|Logan's10thBirthday|Logan's10thBirthday|Logan's 10th Birthday 2017", + "Logan's 11th & Chelsea's 6th Birthday|Logan's11th&Chelsea's6thBirthday|Logan's11th&Chelsea's6thBirthday|Logan's 11th & Chelsea's 6th Birthday 2018", + "Logan's 12th Birthday|Logan's12thBirthday|Logan's12thBirthday|Logan's 12th Birthday 2019", + "Logan's 3rd Birthday|Logan's3rdBirthday|Logan's3rdBirthday|Logan's 3rd Birthday 2010", + "Logan's 4th Birthday|Logan's4thBirthday|Logan's4thBirthday|Logan's 4th Birthday 2011", + "Logan's 6th & Chelsea's 1st Birthday|Logan's6th&Chelsea's1stBirthday|Logan's6th&Chelsea's1stBirthday|Logan's 6th & Chelsea's 1st Birthday 2013", + "Logan's 7th & Chelsea's 2nd Birthday Party|Logan's7th&Chelsea's2ndBirthdayParty|Logan's7th&Chelsea's2ndBirthdayParty|Logan's 7th & Chelsea's 2nd Birthday Party 2014", + "Logan's 7th Birthday|Logan's7thBirthday|Logan's7thBirthday|Logan's 7th Birthday 2014", + "Logan's 8th and Chelsea's 3rd Birthday|Logan's8thAndChelsea's3rdBirthday|Logan's8thAndChelsea's3rdBirthday|Logan's 8th and Chelsea's 3rd Birthday 2015", + "Logan's 9th & Chelsea's 4th Birthday|Logan's9th&Chelsea's4thBirthday|Logan's9th&Chelsea's4thBirthday|Logan's 9th & Chelsea's 4th Birthday 2016", + "Mackara Wedding|MackaraWedding|MackaraWedding|Mackara Wedding 2009", + "Mackenzie 10 Birthday 2010|Mackenzie's 10th Birthday 2010", + "Mackenzie 10 Birthday|Mackenzie10Birthday|Mackenzie10Birthday|Mackenzie's 10th Birthday 2010", + "Mackenzie 11th bday|Mackenzie11thBirthday|Mackenzie11thBirthday|Mackenzie's 11th Birthday 2011", + "Mackenzie 11th Birthday 2011|Mackenzie's 11th Birthday 2011", + "Mackenzie 12 Birthday 2012|Mackenzie's 12th Birthday 2012", + "Mackenzie 12 Birthday|Mackenzie12Birthday|Mackenzie12Birthday|Mackenzie's 12th Birthday 2012", + "Mackenzie 13th Birthday 2013|Mackenzie's 13th Birthday 2013", + "Mackenzie 13th Birthday|Mackenzie13thBirthday|Mackenzie13thBirthday|Mackenzie's 13th Birthday 2013", + "Mackenzie 14 Birthday 2014|Mackenzie's 14 Birthday 2014", + "Mackenzie 14 Birthday|Mackenzie14Birthday|Mackenzie14Birthday|Mackenzie's 14th Birthday 2014", + "Mackenzie 15 Birthday 2015|Mackenzie's 15th Birthday 2015", + "Mackenzie 15 Birthday|Mackenzie15Birthday|Mackenzie15Birthday|Mackenzie's 15th Birthday 2015", + "Mackenzie 4 birthday 2004|Mackenzie's 4th Birthday 2004", + "Mackenzie 4 birthday|Mackenzie4Birthday|Mackenzie4Birthday|Mackenzie's 4th Birthday 2004", + "Mackenzie 5 birthday 2005|Mackenzie's 5th Birthday 2005", + "Mackenzie 5 birthday|Mackenzie5Birthday|Mackenzie5Birthday|Mackenzie's 5th Birthday 2005", + "Mackenzie 5th Grade Graduation|Mackenzie5thGradeGraduation|Mackenzie5thGradeGraduation|Mackenzie 5th Grade Graduation 2010", + "Mackenzie 6 birthday 2006|Mackenzie's 6th Birthday 2006", + "Mackenzie 6 birthday|Mackenzie6Birthday|Mackenzie6Birthday|Mackenzie's 6th Birthday 2006", + "Mackenzie 7 birthday 2007|Mackenzie's 7th Birthday 2007", + "Mackenzie 7 birthday|Mackenzie7Birthday|Mackenzie7Birthday|Mackenzie's 7th Birthday 2007", + "Mackenzie 8 birthday 2008|Mackenzie's 8 Birthday 2008", + "Mackenzie 8 birthday|Mackenzie8Birthday|Mackenzie8Birthday|Mackenzie's 8 Birthday 2008", + "Mackenzie 9 Birthday 2009|Mackenzie's 9th Birthday 2009", + "Mackenzie 9 Birthday|Mackenzie9Birthday|Mackenzie9Birthday|Mackenzie's 9th Birthday 2009", + "Mackenzie Birthday 2017|Mackenzie's 17th Birthday 2017", + "Mackenzie Birthday|Mackenzie's 17th Birthday 2017", + "Mackenzie CA 2016|Mackenzie's 16th Birthday CA 2016", + "Mackenzie End of Year Band Concert 2012|MackenzieEndOfYearBandConcert2012|MackenzieEndOfYearBandConcert2012|Mackenzie Band Concert 2012", + "Mackenzie Surgery|MackenzieSurgery|MackenzieSurgery|Mackenzie Surgery 2009", + "Mackenzie Volleyball|MackenzieVolleyball|MackenzieVolleyball|Mackenzie Volleyball 2012", + "Mackenzie's 14 Birthday 2014|Mackenzie's 14th Birthday 2014", + "Mackenzie's 8 Birthday 2008|Mackenzie's 8th Birthday 2008", + "Mackenzie's 8 Birthday|Mackenzie8Birthday|Mackenzie8Birthday|Mackenzie's 8th Birthday 2008", + "Mackenzie's 8th Birthday|Mackenzie8Birthday|Mackenzie8Birthday|Mackenzie's 8th Birthday 2008", + "Mackenzie's first tooth|Mackenzie'sFirstTooth|Mackenzie'sFirstTooth|Mackenzie's First Tooth 2006", + "Mackenzie's Picture taking|Mackenzie'sPictureTaking|Mackenzie'sPictureTaking|Mackenzie's Picture taking 2011", + "Mandy's Dogs|Mandy'sDogs|Mandy'sDogs|Mandy's Dogs 2008", + "Mandy's Photos|zzz Mandy's Photos 2010", + "Matt's Baby Shower|Matt'sBabyShower|Matt'sBabyShower|Matt's Baby Shower 2008", + "Memorial Day|MemorialDay|MemorialDay|Memorial Day 2015", + "Mom's stuff 2014|. 2004", + "Mom's stuff|. 2004", + "Mother Cabrini Shrine|MotherCabriniShrine|MotherCabriniShrine|Mother Cabrini Shrine 2010", + "Motorcycles 2010|zzz Motorcycles 2010", + "Motorcycles 2013|zzz Motorcycles 2013", + "Motorcycles 2014|zzz Motorcycles 2014", + "Museum 2013|Museum 2004", + "museum012404|Museum 2004", + "Navajo Lake|NavajoLake|NavajoLake|Navajo Lake 2006", + "New Car|zzz Vericruz 2011", + "New folder|Mackenzie 2017", + "New Puppy|NewPuppy|NewPuppy|New Puppy Bandit 2010", + "Nkotb|NKT|NKT|NKOTB 2011", + "Parents trip to Alaska|zzz Parents trip to Alaska", + "Parents Wedding Picture|ParentsWeddingPicture|ParentsWeddingPicture|Parents Wedding Picture 1975", + "Parents Yard 2002|zzz Parents Yard 2002", + "Parents Yard|ParentsYard|ParentsYard|zzz Parents Yard 2002", + "Patrick|zzz Patrick", + "Phares 60th Anniversary|Phares60thAnniversary|Phares60thAnniversary|Phares 60th Anniversary 2010", + "Phares Family Pictures 2018|zzz Phares Family Pictures 2018", + "Phares Slides|zzz Phares Slides", + "Phone Pictures 2010|. 2010", + "Phone Pictures 2011|. 2011", + "Phone Pictures 2012|. 2012", + "Phone Pictures 2013|. 2013", + "Piper|PPR|PPR|Piper 2015", + "Polar Express|PolarExpress|PolarExpress|Polar Express 2010", + "Portrait Innovations April 2008|zzz Portrait Innovations April 2008", + "Portrait Innovations Files 2007|zzz Portrait Innovations Files 2007", + "Portrait Innovations June 08|zzz Portrait Innovations June 2008", + "Portrait Innovations June 2008|zzz Portrait Innovations June 2008", + "Portrait Innovations March 2012|zzz Portrait Innovations March 2012", + "Pueblo Lake|PuebloLake|PuebloLake|Pueblo Lake 2010", + "Puerto Rico|PuertoRico|PuertoRico|Puerto Rico 2006", + "Rex Memorial|zzz Rex Memorial", + "Scaned pictrues of kids|zzz Scanned Pictures Of Kids", + "Scanned Grandma's Quilt|zzz Scanned Grandma's Quilt", + "Scanned Pictrues Of Kids|zzz Scanned Pictures Of Kids", + "Scanned Prints|zzz Scanned Prints", + "Seattle|STL|STL|Seattle 2003", + "Slide in Name Order Originals (622)|zzz Slide in Name Order Originals (622)", + "Snow boarding|SnowBoarding|SnowBoarding|Snow boarding 2000", + "Snow Storm|SnowStorm|SnowStorm|Snow Storm 2006", + "Sophia's Birthday Party|Sophia'sBirthdayParty|Sophia'sBirthdayParty|Sophia's Birthday Party 2009", + "The guys house|TheGuysHouse|TheGuysHouse|The guys house 2000", + "Track 2013|Jason & Mackenzie Track 2013", + "Tracy Picture Partion|zzz Tracy Picture Partition", + "Tracy Picture Partition|zzz Tracy Picture Partition", + "Tracy Pictures 2005|zzz Tracy Pictures 2005", + "Tracy Pictures 2006|zzz Tracy Pictures 2006", + "Tracy Pictures 2007|zzz Tracy Pictures 2007", + "Tracy Pictures 2008|zzz Tracy Pictures 2008", + "Tracy Pictures 2009|zzz Tracy Pictures 2009", + "Tracy Pictures 2010|zzz Tracy Pictures 2010", + "Tracy Pictures 2011|zzz Tracy Pictures 2011", + "Tracy Pictures 2012|zzz Tracy Pictures 2012", + "Tracy Pictures 2013 Jan-July|zzz Tracy Pictures 2013", + "Tracy Pictures 2013 July- Dec|zzz Tracy Pictures 2013", + "Tracy Pictures 2014|zzz Tracy Pictures 2014", + "Tracy Pictures 2015|zzz Tracy Pictures 2015", + "Tracy's Wedding|Tracy'sWedding|Tracy'sWedding|Tracy's Wedding 2002", + "Trip to Colorado 10 2002|Trip to Colorado October 2002", + "Trip to Colorado 10-1-02|Trip to Colorado October 2002", + "Trip to Colorado 6-1-02|Trip to Colorado June 2002", + "Tub 2002|zzz Tub 2002", + "Tub|zzz Tub 2002", + "Vericruz 2011|zzz Vericruz 2011", + "Washington DC|WashingtonDC|WashingtonDC|Washington DC 2010", + "Winter 2015-2016|Winter 2016", + "X Games|XGames|XGames|X Games 2011" + ], + "RenameB": [ + "/zzz Phares Slides/Slides 2015-06-10/Magazine 01|/zzz Phares Slides/Magazine 01", + "/zzz Phares Slides/Slides 2015-06-10/Magazine 02|/zzz Phares Slides/Magazine 02", + "/zzz Phares Slides/Slides 2015-06-10/Magazine 03|/zzz Phares Slides/Magazine 03", + "/zzz Phares Slides/Slides 2015-06-10/Magazine 04|/zzz Phares Slides/Magazine 04", + "/zzz Phares Slides/Slides 2015-06-10/Magazine 05|/zzz Phares Slides/Magazine 05", + "/zzz Phares Slides/Slides 2015-06-10/Magazine 06|/zzz Phares Slides/Magazine 06", + "/zzz Phares Slides/Slides 2015-06-10/Magazine 07|/zzz Phares Slides/Magazine 07", + "/zzz Phares Slides/Slides 2015-06-10/Magazine 08|/zzz Phares Slides/Magazine 08", + "/zzz Phares Slides/Slides 2015-06-10/Magazine 09|/zzz Phares Slides/Magazine 09", + "/zzz Phares Slides/Slides 2015-06-10/Magazine 10|/zzz Phares Slides/Magazine 10", + "/zzz Phares Slides/Slides 2017-03-14/Magazine 11|/zzz Phares Slides/Magazine 11", + "/zzz Phares Slides/Slides 2017-03-14/Magazine 12|/zzz Phares Slides/Magazine 12", + "/zzz Phares Slides/Slides 2017-03-14/Magazine 13|/zzz Phares Slides/Magazine 13", + "/zzz Phares Slides/Slides 2017-03-14/Magazine 14|/zzz Phares Slides/Magazine 14", + "/zzz Phares Slides/Slides 2017-03-14/Magazine 15|/zzz Phares Slides/Magazine 15", + "/zzz Phares Slides/Slides 2017-03-14/Magazine 16|/zzz Phares Slides/Magazine 16", + "/zzz Phares Slides/Slides 2017-03-14/Magazine 17|/zzz Phares Slides/Magazine 17", + "/zzz Phares Slides/Slides 2017-03-14/Magazine 18|/zzz Phares Slides/Magazine 18", + "/zzz Phares Slides/Slides 2017-03-14/Magazine 19|/zzz Phares Slides/Magazine 19", + "/zzz Phares Slides/Slides 2017-03-14/Magazine 20|/zzz Phares Slides/Magazine 20", + "/zzz Phares Slides/Slides 2017-03-14/Magazine 21|/zzz Phares Slides/Magazine 21", + "/zzz Phares Slides/Slides 2017-03-18/Magazine 22|/zzz Phares Slides/Magazine 22", + "/zzz Phares Slides/Slides 2017-03-18/Magazine 23|/zzz Phares Slides/Magazine 23", + "/zzz Phares Slides/Slides 2017-03-18/Magazine 24|/zzz Phares Slides/Magazine 24", + "/zzz Phares Slides/Slides 2017-03-18/Magazine 25|/zzz Phares Slides/Magazine 25", + "/zzz Phares Slides/Slides 2017-10-08/Magazine 26|/zzz Phares Slides/Magazine 26", + "/zzz Phares Slides/Slides 2017-10-08/Magazine 27|/zzz Phares Slides/Magazine 27", + "/zzz Phares Slides/Slides 2017-10-08/Magazine 28|/zzz Phares Slides/Magazine 28", + "/zzz Phares Slides/Slides 2017-10-08/Magazine 29|/zzz Phares Slides/Magazine 29", + "/zzz Phares Slides/Slides 2017-10-08/Magazine 30|/zzz Phares Slides/Magazine 30", + "/zzz Phares Slides/Slides 2017-10-08/Magazine 31|/zzz Phares Slides/Magazine 31", + "/zzz Phares Slides/Slides 2017-10-08/Magazine 32|/zzz Phares Slides/Magazine 32", + "/zzz Phares Slides/Slides 2017-10-08/Magazine 33|/zzz Phares Slides/Magazine 33", + "/zzz Phares Slides/Slides 2017-10-08/Magazine 34|/zzz Phares Slides/Magazine 34", + "/zzz Phares Slides/Slides 2017-10-08/Magazine 35|/zzz Phares Slides/Magazine 35", + "/zzz Phares Slides/Slides 2017-10-08/Magazine 36|/zzz Phares Slides/Magazine 36", + "/zzz Phares Slides/Slides 2017-10-08/Info 01 - 12|/zzz Phares Slides/Info 01 - 12", + "/zzz Phares Slides/Slides 2017-10-08/Info 13 - 22|/zzz Phares Slides/Info 13 - 22", + "/zzz Phares Slides/Slides 2017-10-08/Info 23 - 24|/zzz Phares Slides/Info 23 - 24", + "/zzz Tracy Picture Partition/2005/April 2005|/zzz Tracy Pictures 2005/April 2005", + "/zzz Tracy Picture Partition/2005/August 2005/August 30 2005|/zzz Tracy Pictures 2005/August 2005/August 30 2005", + "/zzz Tracy Picture Partition/2005/August 2005/August 31 2005|/zzz Tracy Pictures 2005/August 2005/August 31 2005", + "/zzz Tracy Picture Partition/2005/December 2005/December 16 2005|/zzz Tracy Pictures 2005/December 2005/December 16 2005", + "/zzz Tracy Picture Partition/2005/December 2005/December 17 2005|/zzz Tracy Pictures 2005/December 2005/December 17 2005", + "/zzz Tracy Picture Partition/2005/December 2005/December 18 2005|/zzz Tracy Pictures 2005/December 2005/December 18 2005", + "/zzz Tracy Picture Partition/2005/December 2005/December 20 2005|/zzz Tracy Pictures 2005/December 2005/December 20 2005", + "/zzz Tracy Picture Partition/2005/December 2005/December 23 2005|/zzz Tracy Pictures 2005/December 2005/December 23 2005", + "/zzz Tracy Picture Partition/2005/December 2005/December 26 2005|/zzz Tracy Pictures 2005/December 2005/December 26 2005", + "/zzz Tracy Picture Partition/2005/December 2005/December 27 2005|/zzz Tracy Pictures 2005/December 2005/December 27 2005", + "/zzz Tracy Picture Partition/2005/December 2005/December 9 2005|/zzz Tracy Pictures 2005/December 2005/December 9 2005", + "/zzz Tracy Picture Partition/2005/December 2005|/zzz Tracy Pictures 2005/December 2005", + "/zzz Tracy Picture Partition/2005/July 2005/July 1 2005|/zzz Tracy Pictures 2005/July 2005/July 1 2005", + "/zzz Tracy Picture Partition/2005/July 2005/July 2 2005|/zzz Tracy Pictures 2005/July 2005/July 2 2005", + "/zzz Tracy Picture Partition/2005/July 2005/July 4 2005|/zzz Tracy Pictures 2005/July 2005/July 4 2005", + "/zzz Tracy Picture Partition/2005/July 2005|/zzz Tracy Pictures 2005/July 2005", + "/zzz Tracy Picture Partition/2005/June 2005/June 28 2005|/zzz Tracy Pictures 2005/June 2005/June 28 2005", + "/zzz Tracy Picture Partition/2005/June 2005/June 29 2005|/zzz Tracy Pictures 2005/June 2005/June 29 2005", + "/zzz Tracy Picture Partition/2005/June 2005/June 30 2005|/zzz Tracy Pictures 2005/June 2005/June 30 2005", + "/zzz Tracy Picture Partition/2005/March 2005|/zzz Tracy Pictures 2005/March 2005", + "/zzz Tracy Picture Partition/2005/MAy 2005|/zzz Tracy Pictures 2005/MAy 2005", + "/zzz Tracy Picture Partition/2005/November 2005/November 13 2005|/zzz Tracy Pictures 2005/November 2005/November 13 2005", + "/zzz Tracy Picture Partition/2005/November 2005/November 16 2005|/zzz Tracy Pictures 2005/November 2005/November 16 2005", + "/zzz Tracy Picture Partition/2005/November 2005/November 18 2005|/zzz Tracy Pictures 2005/November 2005/November 18 2005", + "/zzz Tracy Picture Partition/2005/November 2005/November 20 2005|/zzz Tracy Pictures 2005/November 2005/November 20 2005", + "/zzz Tracy Picture Partition/2005/November 2005/November 23 2005|/zzz Tracy Pictures 2005/November 2005/November 23 2005", + "/zzz Tracy Picture Partition/2005/November 2005/November 24 2005|/zzz Tracy Pictures 2005/November 2005/November 24 2005", + "/zzz Tracy Picture Partition/2005/November 2005/November 28 2005|/zzz Tracy Pictures 2005/November 2005/November 28 2005", + "/zzz Tracy Picture Partition/2005/November 2005/November 30 2005|/zzz Tracy Pictures 2005/November 2005/November 30 2005", + "/zzz Tracy Picture Partition/2005/November 2005/November 4 2005|/zzz Tracy Pictures 2005/November 2005/November 4 2005", + "/zzz Tracy Picture Partition/2005/November 2005/November 5 2005|/zzz Tracy Pictures 2005/November 2005/November 5 2005", + "/zzz Tracy Picture Partition/2005/November 2005/November 6 2005|/zzz Tracy Pictures 2005/November 2005/November 6 2005", + "/zzz Tracy Picture Partition/2005/November 2005|/zzz Tracy Pictures 2005/November 2005", + "/zzz Tracy Picture Partition/2005/October 2005/October 11 2005|/zzz Tracy Pictures 2005/October 2005/October 11 2005", + "/zzz Tracy Picture Partition/2005/October 2005/October 17 2005|/zzz Tracy Pictures 2005/October 2005/October 17 2005", + "/zzz Tracy Picture Partition/2005/October 2005/October 30 2005|/zzz Tracy Pictures 2005/October 2005/October 30 2005", + "/zzz Tracy Picture Partition/2005/October 2005/October 4 2005|/zzz Tracy Pictures 2005/October 2005/October 4 2005", + "/zzz Tracy Picture Partition/2005/October 2005/October 6 2005|/zzz Tracy Pictures 2005/October 2005/October 6 2005", + "/zzz Tracy Picture Partition/2005/October 2005|/zzz Tracy Pictures 2005/October 2005", + "/zzz Tracy Picture Partition/2005/September 2005/September 10 2005|/zzz Tracy Pictures 2005/September 2005/September 10 2005", + "/zzz Tracy Picture Partition/2005/September 2005/September 2 2005|/zzz Tracy Pictures 2005/September 2005/September 2 2005", + "/zzz Tracy Picture Partition/2005/September 2005/September 20 2005|/zzz Tracy Pictures 2005/September 2005/September 20 2005", + "/zzz Tracy Picture Partition/2005/September 2005/September 25 2005|/zzz Tracy Pictures 2005/September 2005/September 25 2005", + "/zzz Tracy Picture Partition/2005/September 2005/September 26 2005|/zzz Tracy Pictures 2005/September 2005/September 26 2005", + "/zzz Tracy Picture Partition/2005/September 2005/September 28 2005|/zzz Tracy Pictures 2005/September 2005/September 28 2005", + "/zzz Tracy Picture Partition/2005/September 2005/September 3 2005|/zzz Tracy Pictures 2005/September 2005/September 3 2005", + "/zzz Tracy Picture Partition/2005/September 2005/September 4 2005|/zzz Tracy Pictures 2005/September 2005/September 4 2005", + "/zzz Tracy Picture Partition/2005/September 2005/September 5 2005|/zzz Tracy Pictures 2005/September 2005/September 5 2005", + "/zzz Tracy Picture Partition/2005/September 2005/September 6 2005|/zzz Tracy Pictures 2005/September 2005/September 6 2005", + "/zzz Tracy Picture Partition/2005/September 2005/September 7 2005|/zzz Tracy Pictures 2005/September 2005/September 7 2005", + "/zzz Tracy Picture Partition/2005/September 2005/September 8 2005|/zzz Tracy Pictures 2005/September 2005/September 8 2005", + "/zzz Tracy Picture Partition/2005/September 2005|/zzz Tracy Pictures 2005/September 2005", + "/zzz Tracy Picture Partition/2006/April 2006/April 12 2006|/zzz Tracy Pictures 2006/April 2006/April 12 2006", + "/zzz Tracy Picture Partition/2006/April 2006/April 14 2006|/zzz Tracy Pictures 2006/April 2006/April 14 2006", + "/zzz Tracy Picture Partition/2006/April 2006/April 16 2006|/zzz Tracy Pictures 2006/April 2006/April 16 2006", + "/zzz Tracy Picture Partition/2006/April 2006/April 17 2006|/zzz Tracy Pictures 2006/April 2006/April 17 2006", + "/zzz Tracy Picture Partition/2006/April 2006/April 18 2006|/zzz Tracy Pictures 2006/April 2006/April 18 2006", + "/zzz Tracy Picture Partition/2006/April 2006/April 19 2006|/zzz Tracy Pictures 2006/April 2006/April 19 2006", + "/zzz Tracy Picture Partition/2006/April 2006/April 20 2006|/zzz Tracy Pictures 2006/April 2006/April 20 2006", + "/zzz Tracy Picture Partition/2006/April 2006/April 21 2006|/zzz Tracy Pictures 2006/April 2006/April 21 2006", + "/zzz Tracy Picture Partition/2006/April 2006/April 23 2006|/zzz Tracy Pictures 2006/April 2006/April 23 2006", + "/zzz Tracy Picture Partition/2006/April 2006/April 24 2006|/zzz Tracy Pictures 2006/April 2006/April 24 2006", + "/zzz Tracy Picture Partition/2006/April 2006/April 25 2006|/zzz Tracy Pictures 2006/April 2006/April 25 2006", + "/zzz Tracy Picture Partition/2006/April 2006/April 3 2006|/zzz Tracy Pictures 2006/April 2006/April 3 2006", + "/zzz Tracy Picture Partition/2006/April 2006/April 6 2006|/zzz Tracy Pictures 2006/April 2006/April 6 2006", + "/zzz Tracy Picture Partition/2006/March 2006/March 27 2006|/zzz Tracy Pictures 2006/March 2006/March 27 2006", + "/zzz Tracy Picture Partition/2006/March 2006/March 28 2006|/zzz Tracy Pictures 2006/March 2006/March 28 2006", + "/zzz Tracy Picture Partition/2006/March 2006/March 29 2006|/zzz Tracy Pictures 2006/March 2006/March 29 2006", + "/zzz Tracy Picture Partition/2006/March 2006/March 30 2006|/zzz Tracy Pictures 2006/March 2006/March 30 2006", + "/zzz Tracy Picture Partition/2007/August 2007/August 10 2007|/zzz Tracy Pictures 2007/August 2007/August 10 2007", + "/zzz Tracy Picture Partition/2007/August 2007/August 6 2007|/zzz Tracy Pictures 2007/August 2007/August 6 2007", + "/zzz Tracy Picture Partition/2007/August 2007/August 7 2007|/zzz Tracy Pictures 2007/August 2007/August 7 2007", + "/zzz Tracy Picture Partition/2007/February 2007/February 10 2007|/zzz Tracy Pictures 2007/February 2007/February 10 2007", + "/zzz Tracy Picture Partition/2007/February 2007/February 13 2007|/zzz Tracy Pictures 2007/February 2007/February 13 2007", + "/zzz Tracy Picture Partition/2007/February 2007/February 15 2007|/zzz Tracy Pictures 2007/February 2007/February 15 2007", + "/zzz Tracy Picture Partition/2007/February 2007/February 16 2007|/zzz Tracy Pictures 2007/February 2007/February 16 2007", + "/zzz Tracy Picture Partition/2007/February 2007/February 19 2007|/zzz Tracy Pictures 2007/February 2007/February 19 2007", + "/zzz Tracy Picture Partition/2007/Febuary 2007/Febuary 10 2007|/zzz Tracy Pictures 2007/Febuary 2007/Febuary 10 2007", + "/zzz Tracy Picture Partition/2007/Febuary 2007/Febuary 13 2007|/zzz Tracy Pictures 2007/Febuary 2007/Febuary 13 2007", + "/zzz Tracy Picture Partition/2007/Febuary 2007/Febuary 15 2007|/zzz Tracy Pictures 2007/Febuary 2007/Febuary 15 2007", + "/zzz Tracy Picture Partition/2007/Febuary 2007/Febuary 16 2007|/zzz Tracy Pictures 2007/Febuary 2007/Febuary 16 2007", + "/zzz Tracy Picture Partition/2007/Febuary 2007/Febuary 19 2007|/zzz Tracy Pictures 2007/Febuary 2007/Febuary 19 2007", + "/zzz Tracy Picture Partition/2007/September 2007/September 5 2007|/zzz Tracy Pictures 2007/September 2007/September 5 2007", + "/zzz Tracy Picture Partition/2007/September 2007|/zzz Tracy Pictures 2007/September 2007", + "/zzz Tracy Picture Partition/2008|/zzz Tracy Pictures 2008", + "/zzz Tracy Picture Partition/2009/December 2009/December 1 2009|/zzz Tracy Pictures 2009/December 2009/December 1 2009", + "/zzz Tracy Picture Partition/2009/December 2009/December 11 2009|/zzz Tracy Pictures 2009/December 2009/December 11 2009", + "/zzz Tracy Picture Partition/2009/December 2009/December 12 2009|/zzz Tracy Pictures 2009/December 2009/December 12 2009", + "/zzz Tracy Picture Partition/2009/December 2009/December 16 2009|/zzz Tracy Pictures 2009/December 2009/December 16 2009", + "/zzz Tracy Picture Partition/2009/December 2009/December 18 2009|/zzz Tracy Pictures 2009/December 2009/December 18 2009", + "/zzz Tracy Picture Partition/2009/December 2009/December 20 2009|/zzz Tracy Pictures 2009/December 2009/December 20 2009", + "/zzz Tracy Picture Partition/2009/December 2009/December 21 2009|/zzz Tracy Pictures 2009/December 2009/December 21 2009", + "/zzz Tracy Picture Partition/2009/December 2009/December 22 2009|/zzz Tracy Pictures 2009/December 2009/December 22 2009", + "/zzz Tracy Picture Partition/2009/December 2009/December 25 2009|/zzz Tracy Pictures 2009/December 2009/December 25 2009", + "/zzz Tracy Picture Partition/2009/December 2009/December 3 2009|/zzz Tracy Pictures 2009/December 2009/December 3 2009", + "/zzz Tracy Picture Partition/2009/December 2009/December 31 2009|/zzz Tracy Pictures 2009/December 2009/December 31 2009", + "/zzz Tracy Picture Partition/2009/February 2009/February 1 2009|/zzz Tracy Pictures 2009/February 2009/February 1 2009", + "/zzz Tracy Picture Partition/2009/February 2009/February 18 2009|/zzz Tracy Pictures 2009/February 2009/February 18 2009", + "/zzz Tracy Picture Partition/2009/February 2009/February 2 2009|/zzz Tracy Pictures 2009/February 2009/February 2 2009", + "/zzz Tracy Picture Partition/2009/February 2009|/zzz Tracy Pictures 2009/February 2009", + "/zzz Tracy Picture Partition/2009/Febuary 2009/Febuary 1 2009|/zzz Tracy Pictures 2009/Febuary 2009/Febuary 1 2009", + "/zzz Tracy Picture Partition/2009/Febuary 2009/Febuary 18 2009|/zzz Tracy Pictures 2009/Febuary 2009/Febuary 18 2009", + "/zzz Tracy Picture Partition/2009/Febuary 2009/Febuary 2 2009|/zzz Tracy Pictures 2009/Febuary 2009/Febuary 2 2009", + "/zzz Tracy Picture Partition/2009/Febuary 2009|/zzz Tracy Pictures 2009/Febuary 2009", + "/zzz Tracy Picture Partition/2009/January 2009/January 12 2009|/zzz Tracy Pictures 2009/January 2009/January 12 2009", + "/zzz Tracy Picture Partition/2009/January 2009/January 13 2009|/zzz Tracy Pictures 2009/January 2009/January 13 2009", + "/zzz Tracy Picture Partition/2009/January 2009/January 14 2009|/zzz Tracy Pictures 2009/January 2009/January 14 2009", + "/zzz Tracy Picture Partition/2009/January 2009/January 15 2009|/zzz Tracy Pictures 2009/January 2009/January 15 2009", + "/zzz Tracy Picture Partition/2009/January 2009/January 19 2009|/zzz Tracy Pictures 2009/January 2009/January 19 2009", + "/zzz Tracy Picture Partition/2009/January 2009/January 27 2009|/zzz Tracy Pictures 2009/January 2009/January 27 2009", + "/zzz Tracy Picture Partition/2009/January 2009/January 28 2009|/zzz Tracy Pictures 2009/January 2009/January 28 2009", + "/zzz Tracy Picture Partition/2009/January 2009/January 29 2009|/zzz Tracy Pictures 2009/January 2009/January 29 2009", + "/zzz Tracy Picture Partition/2009/January 2009/January 4 2009|/zzz Tracy Pictures 2009/January 2009/January 4 2009", + "/zzz Tracy Picture Partition/2009/January 2009/January 6 2009|/zzz Tracy Pictures 2009/January 2009/January 6 2009", + "/zzz Tracy Picture Partition/2009/January 2009/January 9 2009|/zzz Tracy Pictures 2009/January 2009/January 9 2009", + "/zzz Tracy Picture Partition/2009/January 2009|/zzz Tracy Pictures 2009/January 2009", + "/zzz Tracy Picture Partition/2009/November 2009/November 17 2009|/zzz Tracy Pictures 2009/November 2009/November 17 2009", + "/zzz Tracy Picture Partition/2009/November 2009/November 18 2009|/zzz Tracy Pictures 2009/November 2009/November 18 2009", + "/zzz Tracy Picture Partition/2009/November 2009/November 2 2009|/zzz Tracy Pictures 2009/November 2009/November 2 2009", + "/zzz Tracy Picture Partition/2009/November 2009/November 21 2009|/zzz Tracy Pictures 2009/November 2009/November 21 2009", + "/zzz Tracy Picture Partition/2009/November 2009/November 22 2009|/zzz Tracy Pictures 2009/November 2009/November 22 2009", + "/zzz Tracy Picture Partition/2009/November 2009/November 23 2009|/zzz Tracy Pictures 2009/November 2009/November 23 2009", + "/zzz Tracy Picture Partition/2009/November 2009/November 3 2009|/zzz Tracy Pictures 2009/November 2009/November 3 2009", + "/zzz Tracy Picture Partition/2009/November 2009/November 4 2009|/zzz Tracy Pictures 2009/November 2009/November 4 2009", + "/zzz Tracy Picture Partition/2009/November 2009/November 5 2009|/zzz Tracy Pictures 2009/November 2009/November 5 2009", + "/zzz Tracy Picture Partition/2009/November 2009/November 7 2009|/zzz Tracy Pictures 2009/November 2009/November 7 2009", + "/zzz Tracy Picture Partition/2009/October 2009/October 1 2009|/zzz Tracy Pictures 2009/October 2009/October 1 2009", + "/zzz Tracy Picture Partition/2009/October 2009/October 12 2009|/zzz Tracy Pictures 2009/October 2009/October 12 2009", + "/zzz Tracy Picture Partition/2009/October 2009/October 2 2009|/zzz Tracy Pictures 2009/October 2009/October 2 2009", + "/zzz Tracy Picture Partition/2009/October 2009/October 21 2009|/zzz Tracy Pictures 2009/October 2009/October 21 2009", + "/zzz Tracy Picture Partition/2009/October 2009/October 22 2009|/zzz Tracy Pictures 2009/October 2009/October 22 2009", + "/zzz Tracy Picture Partition/2009/October 2009/October 23 2009|/zzz Tracy Pictures 2009/October 2009/October 23 2009", + "/zzz Tracy Picture Partition/2009/October 2009/October 31 2009|/zzz Tracy Pictures 2009/October 2009/October 31 2009", + "/zzz Tracy Picture Partition/2009/October 2009/October 4 2009|/zzz Tracy Pictures 2009/October 2009/October 4 2009", + "/zzz Tracy Picture Partition/2009/October 2009/October 5 2009|/zzz Tracy Pictures 2009/October 2009/October 5 2009", + "/zzz Tracy Picture Partition/2009/October 2009/October 8 2009|/zzz Tracy Pictures 2009/October 2009/October 8 2009", + "/zzz Tracy Picture Partition/2009/October 2009|/zzz Tracy Pictures 2009/October 2009", + "/zzz Tracy Picture Partition/2009/September 2009/September 14 2009|/zzz Tracy Pictures 2009/September 2009/September 14 2009", + "/zzz Tracy Picture Partition/2009/September 2009/September 18 2009|/zzz Tracy Pictures 2009/September 2009/September 18 2009", + "/zzz Tracy Picture Partition/2009/September 2009/September 19 2009|/zzz Tracy Pictures 2009/September 2009/September 19 2009", + "/zzz Tracy Picture Partition/2009/September 2009/September 20 2009|/zzz Tracy Pictures 2009/September 2009/September 20 2009", + "/zzz Tracy Picture Partition/2009/September 2009/September 23 2009|/zzz Tracy Pictures 2009/September 2009/September 23 2009", + "/zzz Tracy Picture Partition/2009/September 2009/September 24 2009|/zzz Tracy Pictures 2009/September 2009/September 24 2009", + "/zzz Tracy Picture Partition/2009/September 2009/September 26 2009|/zzz Tracy Pictures 2009/September 2009/September 26 2009", + "/zzz Tracy Picture Partition/2009/September 2009/September 29 2009|/zzz Tracy Pictures 2009/September 2009/September 29 2009", + "/zzz Tracy Picture Partition/2009/September 2009|/zzz Tracy Pictures 2009/September 2009", + "/zzz Tracy Picture Partition/2010/April 24 2010/April 2 2010|/zzz Tracy Pictures 2010/April 24 2010/April 2 2010", + "/zzz Tracy Picture Partition/2010/April 24 2010/April 24 2010|/zzz Tracy Pictures 2010/April 24 2010/April 24 2010", + "/zzz Tracy Picture Partition/2010/April 24 2010/April 4 2010|/zzz Tracy Pictures 2010/April 24 2010/April 4 2010", + "/zzz Tracy Picture Partition/2010/April 24 2010/April 5 2010|/zzz Tracy Pictures 2010/April 24 2010/April 5 2010", + "/zzz Tracy Picture Partition/2010/April 24 2010/April 7 2010|/zzz Tracy Pictures 2010/April 24 2010/April 7 2010", + "/zzz Tracy Picture Partition/2010/April 24 2010/April 8 2010|/zzz Tracy Pictures 2010/April 24 2010/April 8 2010", + "/zzz Tracy Picture Partition/2010/August 2010/August 12 2010|/zzz Tracy Pictures 2010/August 2010/August 12 2010", + "/zzz Tracy Picture Partition/2010/August 2010/August 14 2010|/zzz Tracy Pictures 2010/August 2010/August 14 2010", + "/zzz Tracy Picture Partition/2010/August 2010/August 15 2010|/zzz Tracy Pictures 2010/August 2010/August 15 2010", + "/zzz Tracy Picture Partition/2010/August 2010/August 7 2010|/zzz Tracy Pictures 2010/August 2010/August 7 2010", + "/zzz Tracy Picture Partition/2010/February 2010/February 13 2010|/zzz Tracy Pictures 2010/February 2010/February 13 2010", + "/zzz Tracy Picture Partition/2010/February 2010/February 14 2010|/zzz Tracy Pictures 2010/February 2010/February 14 2010", + "/zzz Tracy Picture Partition/2010/February 2010/February 19 2010|/zzz Tracy Pictures 2010/February 2010/February 19 2010", + "/zzz Tracy Picture Partition/2010/February 2010/February 28 2010|/zzz Tracy Pictures 2010/February 2010/February 28 2010", + "/zzz Tracy Picture Partition/2010/February 2010/February 4 2010|/zzz Tracy Pictures 2010/February 2010/February 4 2010", + "/zzz Tracy Picture Partition/2010/February 2010/February 9 2010|/zzz Tracy Pictures 2010/February 2010/February 9 2010", + "/zzz Tracy Picture Partition/2010/Febuary 2010/Febuary 13 2010|/zzz Tracy Pictures 2010/Febuary 2010/Febuary 13 2010", + "/zzz Tracy Picture Partition/2010/Febuary 2010/Febuary 14 2010|/zzz Tracy Pictures 2010/Febuary 2010/Febuary 14 2010", + "/zzz Tracy Picture Partition/2010/Febuary 2010/Febuary 19 2010|/zzz Tracy Pictures 2010/Febuary 2010/Febuary 19 2010", + "/zzz Tracy Picture Partition/2010/Febuary 2010/Febuary 28 2010|/zzz Tracy Pictures 2010/Febuary 2010/Febuary 28 2010", + "/zzz Tracy Picture Partition/2010/Febuary 2010/Febuary 4 2010|/zzz Tracy Pictures 2010/Febuary 2010/Febuary 4 2010", + "/zzz Tracy Picture Partition/2010/Febuary 2010/Febuary 9 2010|/zzz Tracy Pictures 2010/Febuary 2010/Febuary 9 2010", + "/zzz Tracy Picture Partition/2010/January 2010/January 1 2010|/zzz Tracy Pictures 2010/January 2010/January 1 2010", + "/zzz Tracy Picture Partition/2010/January 2010/January 11 2010|/zzz Tracy Pictures 2010/January 2010/January 11 2010", + "/zzz Tracy Picture Partition/2010/January 2010/January 16 2010|/zzz Tracy Pictures 2010/January 2010/January 16 2010", + "/zzz Tracy Picture Partition/2010/January 2010/January 17 2010|/zzz Tracy Pictures 2010/January 2010/January 17 2010", + "/zzz Tracy Picture Partition/2010/January 2010/January 24 2010|/zzz Tracy Pictures 2010/January 2010/January 24 2010", + "/zzz Tracy Picture Partition/2010/January 2010/January 31 2010|/zzz Tracy Pictures 2010/January 2010/January 31 2010", + "/zzz Tracy Picture Partition/2010/January 2010/January 4 2010|/zzz Tracy Pictures 2010/January 2010/January 4 2010", + "/zzz Tracy Picture Partition/2010/July 29 2010|/zzz Tracy Pictures 2010/July 29 2010", + "/zzz Tracy Picture Partition/2010/March 2010/March 1 2010|/zzz Tracy Pictures 2010/March 2010/March 1 2010", + "/zzz Tracy Picture Partition/2010/March 2010/March 11 2010|/zzz Tracy Pictures 2010/March 2010/March 11 2010", + "/zzz Tracy Picture Partition/2010/March 2010/March 23 2010|/zzz Tracy Pictures 2010/March 2010/March 23 2010", + "/zzz Tracy Picture Partition/2010/March 2010/March 3 2010|/zzz Tracy Pictures 2010/March 2010/March 3 2010", + "/zzz Tracy Picture Partition/2010/March 2010/March 4 2010|/zzz Tracy Pictures 2010/March 2010/March 4 2010", + "/zzz Tracy Picture Partition/2010/March 2010/March 5 2010|/zzz Tracy Pictures 2010/March 2010/March 5 2010", + "/zzz Tracy Picture Partition/2010/March 2010/March 9 2010|/zzz Tracy Pictures 2010/March 2010/March 9 2010", + "/zzz Tracy Picture Partition/2010/October 18 2010/October 18 2010|/zzz Tracy Pictures 2010/October 18 2010/October 18 2010", + "/zzz Tracy Picture Partition/2010/October 18 2010|/zzz Tracy Pictures 2010/October 18 2010", + "/zzz Tracy Picture Partition/2010|/zzz Tracy Pictures 2010", + "/zzz Tracy Picture Partition/2011/April 2011/April 17 2011|/zzz Tracy Pictures 2011/April 2011/April 17 2011", + "/zzz Tracy Picture Partition/2011/April 2011|/zzz Tracy Pictures 2011/April 2011", + "/zzz Tracy Picture Partition/2011/August 2011/August 10 2011|/zzz Tracy Pictures 2011/August 2011/August 10 2011", + "/zzz Tracy Picture Partition/2011/August 2011/August 19 2011|/zzz Tracy Pictures 2011/August 2011/August 19 2011", + "/zzz Tracy Picture Partition/2011/August 2011/August 31 2011|/zzz Tracy Pictures 2011/August 2011/August 31 2011", + "/zzz Tracy Picture Partition/2011/August 2011/August 5 2011|/zzz Tracy Pictures 2011/August 2011/August 5 2011", + "/zzz Tracy Picture Partition/2011/August 2011|/zzz Tracy Pictures 2011/August 2011", + "/zzz Tracy Picture Partition/2011/December 2011/December 16 2011|/zzz Tracy Pictures 2011/December 2011/December 16 2011", + "/zzz Tracy Picture Partition/2011/December 2011/December 22 2011|/zzz Tracy Pictures 2011/December 2011/December 22 2011", + "/zzz Tracy Picture Partition/2011/December 2011/December 24 2011|/zzz Tracy Pictures 2011/December 2011/December 24 2011", + "/zzz Tracy Picture Partition/2011/December 2011/December 25 2011|/zzz Tracy Pictures 2011/December 2011/December 25 2011", + "/zzz Tracy Picture Partition/2011/December 2011/December 4 2011|/zzz Tracy Pictures 2011/December 2011/December 4 2011", + "/zzz Tracy Picture Partition/2011/December 2011/December 8 2011|/zzz Tracy Pictures 2011/December 2011/December 8 2011", + "/zzz Tracy Picture Partition/2011/December 2011|/zzz Tracy Pictures 2011/December 2011", + "/zzz Tracy Picture Partition/2011/July 2011/July 1 2011|/zzz Tracy Pictures 2011/July 2011/July 1 2011", + "/zzz Tracy Picture Partition/2011/July 2011/July 11 2011|/zzz Tracy Pictures 2011/July 2011/July 11 2011", + "/zzz Tracy Picture Partition/2011/July 2011/July 14 2011|/zzz Tracy Pictures 2011/July 2011/July 14 2011", + "/zzz Tracy Picture Partition/2011/July 2011/July 2 2011|/zzz Tracy Pictures 2011/July 2011/July 2 2011", + "/zzz Tracy Picture Partition/2011/July 2011/July 20 2011|/zzz Tracy Pictures 2011/July 2011/July 20 2011", + "/zzz Tracy Picture Partition/2011/July 2011/July 25 2011|/zzz Tracy Pictures 2011/July 2011/July 25 2011", + "/zzz Tracy Picture Partition/2011/July 2011/July 3 2011|/zzz Tracy Pictures 2011/July 2011/July 3 2011", + "/zzz Tracy Picture Partition/2011/July 2011/July 31 2011|/zzz Tracy Pictures 2011/July 2011/July 31 2011", + "/zzz Tracy Picture Partition/2011/July 2011/July 4 2011|/zzz Tracy Pictures 2011/July 2011/July 4 2011", + "/zzz Tracy Picture Partition/2011/July 2011/July 5 2011|/zzz Tracy Pictures 2011/July 2011/July 5 2011", + "/zzz Tracy Picture Partition/2011/July 2011|/zzz Tracy Pictures 2011/July 2011", + "/zzz Tracy Picture Partition/2011/June 2011/June 28 2011|/zzz Tracy Pictures 2011/June 2011/June 28 2011", + "/zzz Tracy Picture Partition/2011/June 2011/June 29 2011|/zzz Tracy Pictures 2011/June 2011/June 29 2011", + "/zzz Tracy Picture Partition/2011/June 2011/June 30 2011|/zzz Tracy Pictures 2011/June 2011/June 30 2011", + "/zzz Tracy Picture Partition/2011/June 2011|/zzz Tracy Pictures 2011/June 2011", + "/zzz Tracy Picture Partition/2011/March 2011/March 13 2011|/zzz Tracy Pictures 2011/March 2011/March 13 2011", + "/zzz Tracy Picture Partition/2011/March 2011/March 14 2011|/zzz Tracy Pictures 2011/March 2011/March 14 2011", + "/zzz Tracy Picture Partition/2011/March 2011/March 28 2011|/zzz Tracy Pictures 2011/March 2011/March 28 2011", + "/zzz Tracy Picture Partition/2011/March 2011|/zzz Tracy Pictures 2011/March 2011", + "/zzz Tracy Picture Partition/2011/May 2011|/zzz Tracy Pictures 2011/May 2011", + "/zzz Tracy Picture Partition/2011/November 2011/November 1 2011|/zzz Tracy Pictures 2011/November 2011/November 1 2011", + "/zzz Tracy Picture Partition/2011/November 2011/November 12 2011|/zzz Tracy Pictures 2011/November 2011/November 12 2011", + "/zzz Tracy Picture Partition/2011/November 2011/November 13 2011|/zzz Tracy Pictures 2011/November 2011/November 13 2011", + "/zzz Tracy Picture Partition/2011/November 2011/November 19 2011|/zzz Tracy Pictures 2011/November 2011/November 19 2011", + "/zzz Tracy Picture Partition/2011/November 2011/November 21 2011|/zzz Tracy Pictures 2011/November 2011/November 21 2011", + "/zzz Tracy Picture Partition/2011/November 2011/November 24 2011|/zzz Tracy Pictures 2011/November 2011/November 24 2011", + "/zzz Tracy Picture Partition/2011/November 2011/November 9 2011|/zzz Tracy Pictures 2011/November 2011/November 9 2011", + "/zzz Tracy Picture Partition/2011/November 2011|/zzz Tracy Pictures 2011/November 2011", + "/zzz Tracy Picture Partition/2011/October 2011/October 12 2011|/zzz Tracy Pictures 2011/October 2011/October 12 2011", + "/zzz Tracy Picture Partition/2011/October 2011/October 29 2011|/zzz Tracy Pictures 2011/October 2011/October 29 2011", + "/zzz Tracy Picture Partition/2011/October 2011/October 3 2011|/zzz Tracy Pictures 2011/October 2011/October 3 2011", + "/zzz Tracy Picture Partition/2011/October 2011/OCtober 5 2011|/zzz Tracy Pictures 2011/October 2011/OCtober 5 2011", + "/zzz Tracy Picture Partition/2011/October 2011/October 6 2011|/zzz Tracy Pictures 2011/October 2011/October 6 2011", + "/zzz Tracy Picture Partition/2011/October 2011|/zzz Tracy Pictures 2011/October 2011", + "/zzz Tracy Picture Partition/2011/September 2011/September 13 2011|/zzz Tracy Pictures 2011/September 2011/September 13 2011", + "/zzz Tracy Picture Partition/2011/September 2011/September 18 2011|/zzz Tracy Pictures 2011/September 2011/September 18 2011", + "/zzz Tracy Picture Partition/2011/September 2011/September 2 2011|/zzz Tracy Pictures 2011/September 2011/September 2 2011", + "/zzz Tracy Picture Partition/2011/September 2011/September 22 2011|/zzz Tracy Pictures 2011/September 2011/September 22 2011", + "/zzz Tracy Picture Partition/2011/September 2011/September 25 2011|/zzz Tracy Pictures 2011/September 2011/September 25 2011", + "/zzz Tracy Picture Partition/2011/September 2011/September 29 2011|/zzz Tracy Pictures 2011/September 2011/September 29 2011", + "/zzz Tracy Picture Partition/2011/September 2011/September 7 2011|/zzz Tracy Pictures 2011/September 2011/September 7 2011", + "/zzz Tracy Picture Partition/2011/September 2011/September 9 2011|/zzz Tracy Pictures 2011/September 2011/September 9 2011", + "/zzz Tracy Picture Partition/2011/September 2011|/zzz Tracy Pictures 2011/September 2011", + "/zzz Tracy Picture Partition/2011|/zzz Tracy Pictures 2011", + "/zzz Tracy Picture Partition/2012/April 2012/April 17 2012|/zzz Tracy Pictures 2012/April 2012/April 17 2012", + "/zzz Tracy Picture Partition/2012/April 2012/April 18 2012|/zzz Tracy Pictures 2012/April 2012/April 18 2012", + "/zzz Tracy Picture Partition/2012/April 2012/April 3 2012|/zzz Tracy Pictures 2012/April 2012/April 3 2012", + "/zzz Tracy Picture Partition/2012/April 2012/April 7 2012|/zzz Tracy Pictures 2012/April 2012/April 7 2012", + "/zzz Tracy Picture Partition/2012/April 2012/April 9 2012|/zzz Tracy Pictures 2012/April 2012/April 9 2012", + "/zzz Tracy Picture Partition/2012/April 2012|/zzz Tracy Pictures 2012/April 2012", + "/zzz Tracy Picture Partition/2012/August 2012/August 1 2012|/zzz Tracy Pictures 2012/August 2012/August 1 2012", + "/zzz Tracy Picture Partition/2012/August 2012/August 24 2012|/zzz Tracy Pictures 2012/August 2012/August 24 2012", + "/zzz Tracy Picture Partition/2012/August 2012|/zzz Tracy Pictures 2012/August 2012", + "/zzz Tracy Picture Partition/2012/December 2012/December 1 2012|/zzz Tracy Pictures 2012/December 2012/December 1 2012", + "/zzz Tracy Picture Partition/2012/December 2012/December 11 2012|/zzz Tracy Pictures 2012/December 2012/December 11 2012", + "/zzz Tracy Picture Partition/2012/December 2012/December 15 2012|/zzz Tracy Pictures 2012/December 2012/December 15 2012", + "/zzz Tracy Picture Partition/2012/December 2012/December 16 2012|/zzz Tracy Pictures 2012/December 2012/December 16 2012", + "/zzz Tracy Picture Partition/2012/December 2012/December 18 2012|/zzz Tracy Pictures 2012/December 2012/December 18 2012", + "/zzz Tracy Picture Partition/2012/December 2012/December 2 2012|/zzz Tracy Pictures 2012/December 2012/December 2 2012", + "/zzz Tracy Picture Partition/2012/December 2012/December 24 2012|/zzz Tracy Pictures 2012/December 2012/December 24 2012", + "/zzz Tracy Picture Partition/2012/December 2012/December 25 2012|/zzz Tracy Pictures 2012/December 2012/December 25 2012", + "/zzz Tracy Picture Partition/2012/December 2012/December 7 2012|/zzz Tracy Pictures 2012/December 2012/December 7 2012", + "/zzz Tracy Picture Partition/2012/December 2012/December 8 2012|/zzz Tracy Pictures 2012/December 2012/December 8 2012", + "/zzz Tracy Picture Partition/2012/December 2012/December 9 2012|/zzz Tracy Pictures 2012/December 2012/December 9 2012", + "/zzz Tracy Picture Partition/2012/February 2012/February 16 2012|/zzz Tracy Pictures 2012/February 2012/February 16 2012", + "/zzz Tracy Picture Partition/2012/February 2012/February 20 2012|/zzz Tracy Pictures 2012/February 2012/February 20 2012", + "/zzz Tracy Picture Partition/2012/February 2012/Febuary 16 2012|/zzz Tracy Pictures 2012/February 2012/Febuary 16 2012", + "/zzz Tracy Picture Partition/2012/February 2012/Febuary 20 2012|/zzz Tracy Pictures 2012/February 2012/Febuary 20 2012", + "/zzz Tracy Picture Partition/2012/February 2012|/zzz Tracy Pictures 2012/February 2012", + "/zzz Tracy Picture Partition/2012/January 2012/January 20 2012|/zzz Tracy Pictures 2012/January 2012/January 20 2012", + "/zzz Tracy Picture Partition/2012/January 2012|/zzz Tracy Pictures 2012/January 2012", + "/zzz Tracy Picture Partition/2012/July 2012/July 12 2012|/zzz Tracy Pictures 2012/July 2012/July 12 2012", + "/zzz Tracy Picture Partition/2012/July 2012/July 21 2012|/zzz Tracy Pictures 2012/July 2012/July 21 2012", + "/zzz Tracy Picture Partition/2012/July 2012/July 26 2012|/zzz Tracy Pictures 2012/July 2012/July 26 2012", + "/zzz Tracy Picture Partition/2012/July 2012|/zzz Tracy Pictures 2012/July 2012", + "/zzz Tracy Picture Partition/2012/June 2012/June 17 2012|/zzz Tracy Pictures 2012/June 2012/June 17 2012", + "/zzz Tracy Picture Partition/2012/June 2012/June 18 2012|/zzz Tracy Pictures 2012/June 2012/June 18 2012", + "/zzz Tracy Picture Partition/2012/June 2012/June 2 2012|/zzz Tracy Pictures 2012/June 2012/June 2 2012", + "/zzz Tracy Picture Partition/2012/June 2012/June 26 2012|/zzz Tracy Pictures 2012/June 2012/June 26 2012", + "/zzz Tracy Picture Partition/2012/June 2012/June 6 2012|/zzz Tracy Pictures 2012/June 2012/June 6 2012", + "/zzz Tracy Picture Partition/2012/June 2012|/zzz Tracy Pictures 2012/June 2012", + "/zzz Tracy Picture Partition/2012/March 2012/March 14 2012|/zzz Tracy Pictures 2012/March 2012/March 14 2012", + "/zzz Tracy Picture Partition/2012/March 2012/March 17 2012|/zzz Tracy Pictures 2012/March 2012/March 17 2012", + "/zzz Tracy Picture Partition/2012/March 2012/March 20 2012|/zzz Tracy Pictures 2012/March 2012/March 20 2012", + "/zzz Tracy Picture Partition/2012/March 2012/March 30 2012|/zzz Tracy Pictures 2012/March 2012/March 30 2012", + "/zzz Tracy Picture Partition/2012/March 2012/March 6 2012|/zzz Tracy Pictures 2012/March 2012/March 6 2012", + "/zzz Tracy Picture Partition/2012/March 2012/March 8 2012|/zzz Tracy Pictures 2012/March 2012/March 8 2012", + "/zzz Tracy Picture Partition/2012/March 2012|/zzz Tracy Pictures 2012/March 2012", + "/zzz Tracy Picture Partition/2012/May 2012/May 11 2012|/zzz Tracy Pictures 2012/May 2012/May 11 2012", + "/zzz Tracy Picture Partition/2012/May 2012/May 12 2012|/zzz Tracy Pictures 2012/May 2012/May 12 2012", + "/zzz Tracy Picture Partition/2012/May 2012/May 15 2012|/zzz Tracy Pictures 2012/May 2012/May 15 2012", + "/zzz Tracy Picture Partition/2012/May 2012/May 17 2012|/zzz Tracy Pictures 2012/May 2012/May 17 2012", + "/zzz Tracy Picture Partition/2012/May 2012/May 18 2012|/zzz Tracy Pictures 2012/May 2012/May 18 2012", + "/zzz Tracy Picture Partition/2012/May 2012/May 21 2012|/zzz Tracy Pictures 2012/May 2012/May 21 2012", + "/zzz Tracy Picture Partition/2012/May 2012/May 22 2012|/zzz Tracy Pictures 2012/May 2012/May 22 2012", + "/zzz Tracy Picture Partition/2012/May 2012/May 24 2012|/zzz Tracy Pictures 2012/May 2012/May 24 2012", + "/zzz Tracy Picture Partition/2012/May 2012/May 26 2012|/zzz Tracy Pictures 2012/May 2012/May 26 2012", + "/zzz Tracy Picture Partition/2012/May 2012|/zzz Tracy Pictures 2012/May 2012", + "/zzz Tracy Picture Partition/2012/November 2012/November 15 2012|/zzz Tracy Pictures 2012/November 2012/November 15 2012", + "/zzz Tracy Picture Partition/2012/November 2012/November 17 2012|/zzz Tracy Pictures 2012/November 2012/November 17 2012", + "/zzz Tracy Picture Partition/2012/November 2012/November 24 2012|/zzz Tracy Pictures 2012/November 2012/November 24 2012", + "/zzz Tracy Picture Partition/2012/November 2012/November 25 2012|/zzz Tracy Pictures 2012/November 2012/November 25 2012", + "/zzz Tracy Picture Partition/2012/November 2012/November 28 2012|/zzz Tracy Pictures 2012/November 2012/November 28 2012", + "/zzz Tracy Picture Partition/2012/November 2012/November 3 2012|/zzz Tracy Pictures 2012/November 2012/November 3 2012", + "/zzz Tracy Picture Partition/2012/November 2012|/zzz Tracy Pictures 2012/November 2012", + "/zzz Tracy Picture Partition/2012/October 2012/October 17 2012|/zzz Tracy Pictures 2012/October 2012/October 17 2012", + "/zzz Tracy Picture Partition/2012/October 2012/October 24 2012|/zzz Tracy Pictures 2012/October 2012/October 24 2012", + "/zzz Tracy Picture Partition/2012/October 2012/October 27 2012|/zzz Tracy Pictures 2012/October 2012/October 27 2012", + "/zzz Tracy Picture Partition/2012/October 2012/October 28 2012|/zzz Tracy Pictures 2012/October 2012/October 28 2012", + "/zzz Tracy Picture Partition/2012/October 2012/October 30 2012|/zzz Tracy Pictures 2012/October 2012/October 30 2012", + "/zzz Tracy Picture Partition/2012/October 2012/October 31 2012|/zzz Tracy Pictures 2012/October 2012/October 31 2012", + "/zzz Tracy Picture Partition/2012/October 2012/October 7 2012|/zzz Tracy Pictures 2012/October 2012/October 7 2012", + "/zzz Tracy Picture Partition/2012/October 2012|/zzz Tracy Pictures 2012/October 2012", + "/zzz Tracy Picture Partition/2012/Sebtember 2012/September 11 2012|/zzz Tracy Pictures 2012/Sebtember 2012/September 11 2012", + "/zzz Tracy Picture Partition/2012/Sebtember 2012/September 12 2012|/zzz Tracy Pictures 2012/Sebtember 2012/September 12 2012", + "/zzz Tracy Picture Partition/2012/Sebtember 2012/September 16 2012|/zzz Tracy Pictures 2012/Sebtember 2012/September 16 2012", + "/zzz Tracy Picture Partition/2012/Sebtember 2012/September 19 2012|/zzz Tracy Pictures 2012/Sebtember 2012/September 19 2012", + "/zzz Tracy Picture Partition/2012/Sebtember 2012/September 28 2012|/zzz Tracy Pictures 2012/Sebtember 2012/September 28 2012", + "/zzz Tracy Picture Partition/2012/Sebtember 2012/September 29 2012|/zzz Tracy Pictures 2012/Sebtember 2012/September 29 2012", + "/zzz Tracy Picture Partition/2012/Sebtember 2012/September 30 2012|/zzz Tracy Pictures 2012/Sebtember 2012/September 30 2012", + "/zzz Tracy Picture Partition/2012/September 2012/September 11 2012|/zzz Tracy Pictures 2012/September 2012/September 11 2012", + "/zzz Tracy Picture Partition/2012/September 2012/September 12 2012|/zzz Tracy Pictures 2012/September 2012/September 12 2012", + "/zzz Tracy Picture Partition/2012/September 2012/September 16 2012|/zzz Tracy Pictures 2012/September 2012/September 16 2012", + "/zzz Tracy Picture Partition/2012/September 2012/September 19 2012|/zzz Tracy Pictures 2012/September 2012/September 19 2012", + "/zzz Tracy Picture Partition/2012/September 2012/September 28 2012|/zzz Tracy Pictures 2012/September 2012/September 28 2012", + "/zzz Tracy Picture Partition/2012/September 2012/September 29 2012|/zzz Tracy Pictures 2012/September 2012/September 29 2012", + "/zzz Tracy Picture Partition/2012/September 2012/September 30 2012|/zzz Tracy Pictures 2012/September 2012/September 30 2012", + "/zzz Tracy Picture Partition/2013 Jan-July/April 2013/April 11 2013|/zzz Tracy Pictures 2013/April 2013/April 11 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/April 2013/April 17 2013|/zzz Tracy Pictures 2013/April 2013/April 17 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/April 2013/April 19 2013|/zzz Tracy Pictures 2013/April 2013/April 19 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/April 2013/April 21 2013|/zzz Tracy Pictures 2013/April 2013/April 21 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/April 2013/April 25 2013|/zzz Tracy Pictures 2013/April 2013/April 25 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/April 2013/April 28 2013|/zzz Tracy Pictures 2013/April 2013/April 28 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/February 2013|/zzz Tracy Pictures 2013/February 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/February 2013/February 23 2013|/zzz Tracy Pictures 2013/February 2013/February 23 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/February 2013/February 24 2013|/zzz Tracy Pictures 2013/February 2013/February 24 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/February 2013/February 5 2013|/zzz Tracy Pictures 2013/February 2013/February 5 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/February 2013/February 7 2013|/zzz Tracy Pictures 2013/February 2013/February 7 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/February 2013/Febuary 23 2013|/zzz Tracy Pictures 2013/Febuary 2013/Febuary 23 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/February 2013/Febuary 24 2013|/zzz Tracy Pictures 2013/Febuary 2013/Febuary 24 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/February 2013/Febuary 5 2013|/zzz Tracy Pictures 2013/Febuary 2013/Febuary 5 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/February 2013/Febuary 7 2013|/zzz Tracy Pictures 2013/Febuary 2013/Febuary 7 2013", + "/zzz Tracy Picture Partition/2013 Jan-July|/zzz Tracy Pictures 2013/January 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/January 2013/January 20 2013|/zzz Tracy Pictures 2013/January 2013/January 20 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/January 2013/January 25 2013|/zzz Tracy Pictures 2013/January 2013/January 25 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/July 2013|/zzz Tracy Pictures 2013/July 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/July 2013/July 13 2013|/zzz Tracy Pictures 2013/July 2013/July 13 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/July 2013/July 14 2013|/zzz Tracy Pictures 2013/July 2013/July 14 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/July 2013/July 3 2013|/zzz Tracy Pictures 2013/July 2013/July 3 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/July 2013/July 6 2013|/zzz Tracy Pictures 2013/July 2013/July 6 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/June 2013|/zzz Tracy Pictures 2013/June 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/June 2013/June 1 2013|/zzz Tracy Pictures 2013/June 2013/June 1 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/June 2013/June 10 2013|/zzz Tracy Pictures 2013/June 2013/June 10 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/June 2013/June 15 2013|/zzz Tracy Pictures 2013/June 2013/June 15 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/June 2013/June 16 2013|/zzz Tracy Pictures 2013/June 2013/June 16 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/June 2013/June 18 2013|/zzz Tracy Pictures 2013/June 2013/June 18 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/June 2013/June 19 2013|/zzz Tracy Pictures 2013/June 2013/June 19 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/June 2013/June 26 2013|/zzz Tracy Pictures 2013/June 2013/June 26 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/June 2013/June 28 2013|/zzz Tracy Pictures 2013/June 2013/June 28 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/June 2013/June 3 2013|/zzz Tracy Pictures 2013/June 2013/June 3 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/June 2013/June 9 2013|/zzz Tracy Pictures 2013/June 2013/June 9 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/March 2013|/zzz Tracy Pictures 2013/March 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/March 2013/March 16 2013|/zzz Tracy Pictures 2013/March 2013/March 16 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/March 2013/March 19 2013|/zzz Tracy Pictures 2013/March 2013/March 19 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/March 2013/March 28 2013|/zzz Tracy Pictures 2013/March 2013/March 28 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/March 2013/March 30 2013|/zzz Tracy Pictures 2013/March 2013/March 30 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/March 2013/March 31 2013|/zzz Tracy Pictures 2013/March 2013/March 31 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/May 2013/May 1 2013|/zzz Tracy Pictures 2013/May 2013/May 1 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/May 2013/May 12 2013|/zzz Tracy Pictures 2013/May 2013/May 12 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/May 2013/May 21 2013|/zzz Tracy Pictures 2013/May 2013/May 21 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/May 2013/May 29 2013|/zzz Tracy Pictures 2013/May 2013/May 29 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/May 2013/May 30 2013|/zzz Tracy Pictures 2013/May 2013/May 30 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/May 2013/May 31 2013|/zzz Tracy Pictures 2013/May 2013/May 31 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/May 2013/May 8 2013|/zzz Tracy Pictures 2013/May 2013/May 8 2013", + "/zzz Tracy Picture Partition/2013 Jan-July/May 2013/May 9 2014|/zzz Tracy Pictures 2013/May 2013/May 9 2014", + "/zzz Tracy Picture Partition/2013 July- Dec/August 2013/August 14 2013|/zzz Tracy Pictures 2013/August 2013/August 14 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/August 2013/August 18 2013|/zzz Tracy Pictures 2013/August 2013/August 18 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/August 2013/August 19 2013|/zzz Tracy Pictures 2013/August 2013/August 19 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/August 2013/August 2 2013|/zzz Tracy Pictures 2013/August 2013/August 2 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/December 2013|/zzz Tracy Pictures 2013/December 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/December 2013/December 10 2013|/zzz Tracy Pictures 2013/December 2013/December 10 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/December 2013/December 23 2013|/zzz Tracy Pictures 2013/December 2013/December 23 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/December 2013/December 24 2013|/zzz Tracy Pictures 2013/December 2013/December 24 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/December 2013/December 9 2013|/zzz Tracy Pictures 2013/December 2013/December 9 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/July 2013/July 3 2013|/zzz Tracy Pictures 2013/July 3 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/November 2013|/zzz Tracy Pictures 2013/November 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/November 2013/November 15 2013|/zzz Tracy Pictures 2013/November 2013/November 15 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/November 2013/November 16 2013|/zzz Tracy Pictures 2013/November 2013/November 16 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/November 2013/November 20 2013|/zzz Tracy Pictures 2013/November 2013/November 20 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/November 2013/November 22 2013|/zzz Tracy Pictures 2013/November 2013/November 22 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/November 2013/November 28 2013|/zzz Tracy Pictures 2013/November 2013/November 28 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/October 2013|/zzz Tracy Pictures 2013/October 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/October 2013/October 12 2013|/zzz Tracy Pictures 2013/October 2013/October 12 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/October 2013/October 2 2013|/zzz Tracy Pictures 2013/October 2013/October 2 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/October 2013/October 20 2013|/zzz Tracy Pictures 2013/October 2013/October 20 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/October 2013/October 3 2013|/zzz Tracy Pictures 2013/October 2013/October 3 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/October 2013/OCtober 31 2013|/zzz Tracy Pictures 2013/October 2013/OCtober 31 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/September 2013|/zzz Tracy Pictures 2013/September 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/September 2013/September 1 2013|/zzz Tracy Pictures 2013/September 2013/September 1 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/September 2013/September 18 2013|/zzz Tracy Pictures 2013/September 2013/September 18 2013", + "/zzz Tracy Picture Partition/2013 July- Dec/September 2013/September 27 2013|/zzz Tracy Pictures 2013/September 2013/September 27 2013", + "/zzz Tracy Picture Partition/2014/April 2014/April 17 2014|/zzz Tracy Pictures 2014/April 2014/April 17 2014", + "/zzz Tracy Picture Partition/2014/April 2014/April 27 2014|/zzz Tracy Pictures 2014/April 2014/April 27 2014", + "/zzz Tracy Picture Partition/2014/April 2014/April 30 2014|/zzz Tracy Pictures 2014/April 2014/April 30 2014", + "/zzz Tracy Picture Partition/2014/April 2014/April 9 2014|/zzz Tracy Pictures 2014/April 2014/April 9 2014", + "/zzz Tracy Picture Partition/2014/April 2014|/zzz Tracy Pictures 2014/April 2014", + "/zzz Tracy Picture Partition/2014/December 2014/December 19 2014|/zzz Tracy Pictures 2014/December 2014/December 19 2014", + "/zzz Tracy Picture Partition/2014/December 2014/December 20 2014|/zzz Tracy Pictures 2014/December 2014/December 20 2014", + "/zzz Tracy Picture Partition/2014/December 2014/December 24 2014|/zzz Tracy Pictures 2014/December 2014/December 24 2014", + "/zzz Tracy Picture Partition/2014/December 2014/December 25 2014|/zzz Tracy Pictures 2014/December 2014/December 25 2014", + "/zzz Tracy Picture Partition/2014/February 2014/February 27 2014|/zzz Tracy Pictures 2014/February 2014/February 27 2014", + "/zzz Tracy Picture Partition/2014/February 2014/February 8 2014|/zzz Tracy Pictures 2014/February 2014/February 8 2014", + "/zzz Tracy Picture Partition/2014/February 2014|/zzz Tracy Pictures 2014/February 2014", + "/zzz Tracy Picture Partition/2014/Febuary 2014/Febuary 27 2014|/zzz Tracy Pictures 2014/Febuary 2014/Febuary 27 2014", + "/zzz Tracy Picture Partition/2014/Febuary 2014/Febuary 8 2014|/zzz Tracy Pictures 2014/Febuary 2014/Febuary 8 2014", + "/zzz Tracy Picture Partition/2014/Febuary 2014|/zzz Tracy Pictures 2014/Febuary 2014", + "/zzz Tracy Picture Partition/2014/January 2014/January 20 2014|/zzz Tracy Pictures 2014/January 2014/January 20 2014", + "/zzz Tracy Picture Partition/2014/January 2014/January 31 2014|/zzz Tracy Pictures 2014/January 2014/January 31 2014", + "/zzz Tracy Picture Partition/2014/January 2014/January 4 2014|/zzz Tracy Pictures 2014/January 2014/January 4 2014", + "/zzz Tracy Picture Partition/2014/January 2014|/zzz Tracy Pictures 2014/January 2014", + "/zzz Tracy Picture Partition/2014/July 2014/July 19 2014|/zzz Tracy Pictures 2014/July 2014/July 19 2014", + "/zzz Tracy Picture Partition/2014/July 2014|/zzz Tracy Pictures 2014/July 2014", + "/zzz Tracy Picture Partition/2014/June 2014/June 17 2014|/zzz Tracy Pictures 2014/June 2014/June 17 2014", + "/zzz Tracy Picture Partition/2014/June 2014/June 20 2014|/zzz Tracy Pictures 2014/June 2014/June 20 2014", + "/zzz Tracy Picture Partition/2014/June 2014/June 21 2014|/zzz Tracy Pictures 2014/June 2014/June 21 2014", + "/zzz Tracy Picture Partition/2014/June 2014|/zzz Tracy Pictures 2014/June 2014", + "/zzz Tracy Picture Partition/2014/March 2014|/zzz Tracy Pictures 2014/March 2014", + "/zzz Tracy Picture Partition/2014/May 2014/May 15 2014|/zzz Tracy Pictures 2014/May 2014/May 15 2014", + "/zzz Tracy Picture Partition/2014/May 2014/May 17 2014|/zzz Tracy Pictures 2014/May 2014/May 17 2014", + "/zzz Tracy Picture Partition/2014/May 2014/May 22 2014|/zzz Tracy Pictures 2014/May 2014/May 22 2014", + "/zzz Tracy Picture Partition/2014/May 2014/May 23 2014|/zzz Tracy Pictures 2014/May 2014/May 23 2014", + "/zzz Tracy Picture Partition/2014/May 2014/May 24 2014|/zzz Tracy Pictures 2014/May 2014/May 24 2014", + "/zzz Tracy Picture Partition/2014/May 2014/May 25 2014|/zzz Tracy Pictures 2014/May 2014/May 25 2014", + "/zzz Tracy Picture Partition/2014/May 2014/May 26 2014|/zzz Tracy Pictures 2014/May 2014/May 26 2014", + "/zzz Tracy Picture Partition/2014/May 2014/May 3 2012 j bday|/zzz Tracy Pictures 2014/May 2014/May 3 2012 j bday", + "/zzz Tracy Picture Partition/2014/May 2014/May 6 2014|/zzz Tracy Pictures 2014/May 2014/May 6 2014", + "/zzz Tracy Picture Partition/2014/May 2014/May 9 2014|/zzz Tracy Pictures 2014/May 2014/May 9 2014", + "/zzz Tracy Picture Partition/2014/November 2014/November 2 2014|/zzz Tracy Pictures 2014/November 2014/November 2 2014", + "/zzz Tracy Picture Partition/2014/November 2014/November 20 2014|/zzz Tracy Pictures 2014/November 2014/November 20 2014", + "/zzz Tracy Picture Partition/2014/November 2014/November 23 2014|/zzz Tracy Pictures 2014/November 2014/November 23 2014", + "/zzz Tracy Picture Partition/2014/November 2014/November 24 2014|/zzz Tracy Pictures 2014/November 2014/November 24 2014", + "/zzz Tracy Picture Partition/2014/November 2014/November 27 2014|/zzz Tracy Pictures 2014/November 2014/November 27 2014", + "/zzz Tracy Picture Partition/2014/November 2014/November 29 2014|/zzz Tracy Pictures 2014/November 2014/November 29 2014", + "/zzz Tracy Picture Partition/2014/November 2014/November 3 2014|/zzz Tracy Pictures 2014/November 2014/November 3 2014", + "/zzz Tracy Picture Partition/2014/November 2014|/zzz Tracy Pictures 2014/November 2014", + "/zzz Tracy Picture Partition/2014/October 2014/October 11 2014|/zzz Tracy Pictures 2014/October 2014/October 11 2014", + "/zzz Tracy Picture Partition/2014/October 2014/October 17 2014|/zzz Tracy Pictures 2014/October 2014/October 17 2014", + "/zzz Tracy Picture Partition/2014/October 2014/October 18 2014|/zzz Tracy Pictures 2014/October 2014/October 18 2014", + "/zzz Tracy Picture Partition/2014/October 2014/October 24 2014|/zzz Tracy Pictures 2014/October 2014/October 24 2014", + "/zzz Tracy Picture Partition/2014/October 2014/October 26 2014|/zzz Tracy Pictures 2014/October 2014/October 26 2014", + "/zzz Tracy Picture Partition/2014/October 2014/October 30 2014|/zzz Tracy Pictures 2014/October 2014/October 30 2014", + "/zzz Tracy Picture Partition/2014/October 2014/OCtober 31 2014|/zzz Tracy Pictures 2014/October 2014/OCtober 31 2014", + "/zzz Tracy Picture Partition/2014/October 2014/October 8 2014|/zzz Tracy Pictures 2014/October 2014/October 8 2014", + "/zzz Tracy Picture Partition/2014/October 2014|/zzz Tracy Pictures 2014/October 2014", + "/zzz Tracy Picture Partition/2014/September 2014/September 12 2014|/zzz Tracy Pictures 2014/September 2014/September 12 2014", + "/zzz Tracy Picture Partition/2014/September 2014/September 20 2014|/zzz Tracy Pictures 2014/September 2014/September 20 2014", + "/zzz Tracy Picture Partition/2014/September 2014|/zzz Tracy Pictures 2014/September 2014", + "/zzz Tracy Picture Partition/2015/Copied from user Tracy/2015-01-01|/zzz Tracy Pictures 2015/Copied from user Tracy/2015-01-01" + ], + "RenameC": [ + "/Chelsea 2012", + "/Chelsea 2013", + "/Logan Michael 2007/Back to the hospital", + "/Logan Michael 2007/Birthday", + "/Logan Michael 2007/Dec 07", + "/Logan Michael 2007/Nov 07", + "/Logan Michael 2007/Oct 07", + "/Logan Michael 2007/Sept 07", + "/Logan Michael 2008/April 08", + "/Logan Michael 2008/Aug 08", + "/Logan Michael 2008/Feb 08", + "/Logan Michael 2008/Jan 08", + "/Logan Michael 2008/July 08", + "/Logan Michael 2008/June 08", + "/Logan Michael 2008/March 08", + "/Logan Michael 2008/May 08", + "/Logan Michael 2008/Nov 08", + "/Logan Michael 2008/Oct 08", + "/Logan Michael 2008/Sept 08", + "/Logan Michael 2009/April 09", + "/Logan Michael 2009/Aug Sept 09", + "/Logan Michael 2009/Dec 09", + "/Logan Michael 2009/Jan 09", + "/Logan Michael 2009/July 09", + "/Logan Michael 2009/June 09", + "/Logan Michael 2009/March 09", + "/Logan Michael 2009/May 09", + "/Logan Michael 2009/Nov 09", + "/Logan Michael 2009/Oct 09", + "/Logan Michael 2010/Jan 10", + "/Logan Michael 2010/March 10", + "/Logan Michael 2010/Oct 2010", + "/zzz Tracy Pictures 2005/April 2005", + "/zzz Tracy Pictures 2005/August 2005/August 30 2005", + "/zzz Tracy Pictures 2005/August 2005/August 31 2005", + "/zzz Tracy Pictures 2005/December 2005", + "/zzz Tracy Pictures 2005/December 2005/December 16 2005", + "/zzz Tracy Pictures 2005/December 2005/December 17 2005", + "/zzz Tracy Pictures 2005/December 2005/December 18 2005", + "/zzz Tracy Pictures 2005/December 2005/December 20 2005", + "/zzz Tracy Pictures 2005/December 2005/December 23 2005", + "/zzz Tracy Pictures 2005/December 2005/December 26 2005", + "/zzz Tracy Pictures 2005/December 2005/December 27 2005", + "/zzz Tracy Pictures 2005/December 2005/December 9 2005", + "/zzz Tracy Pictures 2005/July 2005", + "/zzz Tracy Pictures 2005/July 2005/July 1 2005", + "/zzz Tracy Pictures 2005/July 2005/July 2 2005", + "/zzz Tracy Pictures 2005/July 2005/July 4 2005", + "/zzz Tracy Pictures 2005/June 2005/June 28 2005", + "/zzz Tracy Pictures 2005/June 2005/June 29 2005", + "/zzz Tracy Pictures 2005/June 2005/June 30 2005", + "/zzz Tracy Pictures 2005/March 2005", + "/zzz Tracy Pictures 2005/MAy 2005", + "/zzz Tracy Pictures 2005/November 2005", + "/zzz Tracy Pictures 2005/November 2005/November 13 2005", + "/zzz Tracy Pictures 2005/November 2005/November 16 2005", + "/zzz Tracy Pictures 2005/November 2005/November 18 2005", + "/zzz Tracy Pictures 2005/November 2005/November 20 2005", + "/zzz Tracy Pictures 2005/November 2005/November 23 2005", + "/zzz Tracy Pictures 2005/November 2005/November 24 2005", + "/zzz Tracy Pictures 2005/November 2005/November 28 2005", + "/zzz Tracy Pictures 2005/November 2005/November 30 2005", + "/zzz Tracy Pictures 2005/November 2005/November 4 2005", + "/zzz Tracy Pictures 2005/November 2005/November 5 2005", + "/zzz Tracy Pictures 2005/November 2005/November 6 2005", + "/zzz Tracy Pictures 2005/October 2005", + "/zzz Tracy Pictures 2005/October 2005/October 11 2005", + "/zzz Tracy Pictures 2005/October 2005/October 17 2005", + "/zzz Tracy Pictures 2005/October 2005/October 30 2005", + "/zzz Tracy Pictures 2005/October 2005/October 4 2005", + "/zzz Tracy Pictures 2005/October 2005/October 6 2005", + "/zzz Tracy Pictures 2005/September 2005", + "/zzz Tracy Pictures 2005/September 2005/September 10 2005", + "/zzz Tracy Pictures 2005/September 2005/September 2 2005", + "/zzz Tracy Pictures 2005/September 2005/September 20 2005", + "/zzz Tracy Pictures 2005/September 2005/September 25 2005", + "/zzz Tracy Pictures 2005/September 2005/September 26 2005", + "/zzz Tracy Pictures 2005/September 2005/September 28 2005", + "/zzz Tracy Pictures 2005/September 2005/September 3 2005", + "/zzz Tracy Pictures 2005/September 2005/September 4 2005", + "/zzz Tracy Pictures 2005/September 2005/September 5 2005", + "/zzz Tracy Pictures 2005/September 2005/September 6 2005", + "/zzz Tracy Pictures 2005/September 2005/September 7 2005", + "/zzz Tracy Pictures 2005/September 2005/September 8 2005", + "/zzz Tracy Pictures 2006/April 2006/April 12 2006", + "/zzz Tracy Pictures 2006/April 2006/April 14 2006", + "/zzz Tracy Pictures 2006/April 2006/April 16 2006", + "/zzz Tracy Pictures 2006/April 2006/April 17 2006", + "/zzz Tracy Pictures 2006/April 2006/April 18 2006", + "/zzz Tracy Pictures 2006/April 2006/April 19 2006", + "/zzz Tracy Pictures 2006/April 2006/April 20 2006", + "/zzz Tracy Pictures 2006/April 2006/April 21 2006", + "/zzz Tracy Pictures 2006/April 2006/April 23 2006", + "/zzz Tracy Pictures 2006/April 2006/April 24 2006", + "/zzz Tracy Pictures 2006/April 2006/April 25 2006", + "/zzz Tracy Pictures 2006/April 2006/April 3 2006", + "/zzz Tracy Pictures 2006/April 2006/April 6 2006", + "/zzz Tracy Pictures 2006/March 2006/March 27 2006", + "/zzz Tracy Pictures 2006/March 2006/March 28 2006", + "/zzz Tracy Pictures 2006/March 2006/March 29 2006", + "/zzz Tracy Pictures 2006/March 2006/March 30 2006", + "/zzz Tracy Pictures 2007/August 2007/August 10 2007", + "/zzz Tracy Pictures 2007/August 2007/August 6 2007", + "/zzz Tracy Pictures 2007/August 2007/August 7 2007", + "/zzz Tracy Pictures 2007/February 2007/February 10 2007", + "/zzz Tracy Pictures 2007/February 2007/February 13 2007", + "/zzz Tracy Pictures 2007/February 2007/February 15 2007", + "/zzz Tracy Pictures 2007/February 2007/February 16 2007", + "/zzz Tracy Pictures 2007/February 2007/February 19 2007", + "/zzz Tracy Pictures 2007/Febuary 2007/Febuary 10 2007", + "/zzz Tracy Pictures 2007/Febuary 2007/Febuary 13 2007", + "/zzz Tracy Pictures 2007/Febuary 2007/Febuary 15 2007", + "/zzz Tracy Pictures 2007/Febuary 2007/Febuary 16 2007", + "/zzz Tracy Pictures 2007/Febuary 2007/Febuary 19 2007", + "/zzz Tracy Pictures 2007/September 2007", + "/zzz Tracy Pictures 2007/September 2007/September 5 2007", + "/zzz Tracy Pictures 2008", + "/zzz Tracy Pictures 2009/December 2009/December 1 2009", + "/zzz Tracy Pictures 2009/December 2009/December 11 2009", + "/zzz Tracy Pictures 2009/December 2009/December 12 2009", + "/zzz Tracy Pictures 2009/December 2009/December 16 2009", + "/zzz Tracy Pictures 2009/December 2009/December 18 2009", + "/zzz Tracy Pictures 2009/December 2009/December 20 2009", + "/zzz Tracy Pictures 2009/December 2009/December 21 2009", + "/zzz Tracy Pictures 2009/December 2009/December 22 2009", + "/zzz Tracy Pictures 2009/December 2009/December 25 2009", + "/zzz Tracy Pictures 2009/December 2009/December 3 2009", + "/zzz Tracy Pictures 2009/December 2009/December 31 2009", + "/zzz Tracy Pictures 2009/February 2009", + "/zzz Tracy Pictures 2009/February 2009/February 1 2009", + "/zzz Tracy Pictures 2009/February 2009/February 18 2009", + "/zzz Tracy Pictures 2009/February 2009/February 2 2009", + "/zzz Tracy Pictures 2009/Febuary 2009", + "/zzz Tracy Pictures 2009/Febuary 2009/Febuary 1 2009", + "/zzz Tracy Pictures 2009/Febuary 2009/Febuary 18 2009", + "/zzz Tracy Pictures 2009/Febuary 2009/Febuary 2 2009", + "/zzz Tracy Pictures 2009/January 2009", + "/zzz Tracy Pictures 2009/January 2009/January 12 2009", + "/zzz Tracy Pictures 2009/January 2009/January 13 2009", + "/zzz Tracy Pictures 2009/January 2009/January 14 2009", + "/zzz Tracy Pictures 2009/January 2009/January 15 2009", + "/zzz Tracy Pictures 2009/January 2009/January 19 2009", + "/zzz Tracy Pictures 2009/January 2009/January 27 2009", + "/zzz Tracy Pictures 2009/January 2009/January 28 2009", + "/zzz Tracy Pictures 2009/January 2009/January 29 2009", + "/zzz Tracy Pictures 2009/January 2009/January 4 2009", + "/zzz Tracy Pictures 2009/January 2009/January 6 2009", + "/zzz Tracy Pictures 2009/January 2009/January 9 2009", + "/zzz Tracy Pictures 2009/November 2009/November 17 2009", + "/zzz Tracy Pictures 2009/November 2009/November 18 2009", + "/zzz Tracy Pictures 2009/November 2009/November 2 2009", + "/zzz Tracy Pictures 2009/November 2009/November 21 2009", + "/zzz Tracy Pictures 2009/November 2009/November 22 2009", + "/zzz Tracy Pictures 2009/November 2009/November 23 2009", + "/zzz Tracy Pictures 2009/November 2009/November 3 2009", + "/zzz Tracy Pictures 2009/November 2009/November 4 2009", + "/zzz Tracy Pictures 2009/November 2009/November 5 2009", + "/zzz Tracy Pictures 2009/November 2009/November 7 2009", + "/zzz Tracy Pictures 2009/October 2009", + "/zzz Tracy Pictures 2009/October 2009/October 1 2009", + "/zzz Tracy Pictures 2009/October 2009/October 12 2009", + "/zzz Tracy Pictures 2009/October 2009/October 2 2009", + "/zzz Tracy Pictures 2009/October 2009/October 21 2009", + "/zzz Tracy Pictures 2009/October 2009/October 22 2009", + "/zzz Tracy Pictures 2009/October 2009/October 23 2009", + "/zzz Tracy Pictures 2009/October 2009/October 31 2009", + "/zzz Tracy Pictures 2009/October 2009/October 4 2009", + "/zzz Tracy Pictures 2009/October 2009/October 5 2009", + "/zzz Tracy Pictures 2009/October 2009/October 8 2009", + "/zzz Tracy Pictures 2009/September 2009", + "/zzz Tracy Pictures 2009/September 2009/September 14 2009", + "/zzz Tracy Pictures 2009/September 2009/September 18 2009", + "/zzz Tracy Pictures 2009/September 2009/September 19 2009", + "/zzz Tracy Pictures 2009/September 2009/September 20 2009", + "/zzz Tracy Pictures 2009/September 2009/September 23 2009", + "/zzz Tracy Pictures 2009/September 2009/September 24 2009", + "/zzz Tracy Pictures 2009/September 2009/September 26 2009", + "/zzz Tracy Pictures 2009/September 2009/September 29 2009", + "/zzz Tracy Pictures 2010", + "/zzz Tracy Pictures 2010/April 24 2010/April 2 2010", + "/zzz Tracy Pictures 2010/April 24 2010/April 24 2010", + "/zzz Tracy Pictures 2010/April 24 2010/April 4 2010", + "/zzz Tracy Pictures 2010/April 24 2010/April 5 2010", + "/zzz Tracy Pictures 2010/April 24 2010/April 7 2010", + "/zzz Tracy Pictures 2010/April 24 2010/April 8 2010", + "/zzz Tracy Pictures 2010/August 2010/August 12 2010", + "/zzz Tracy Pictures 2010/August 2010/August 14 2010", + "/zzz Tracy Pictures 2010/August 2010/August 15 2010", + "/zzz Tracy Pictures 2010/August 2010/August 7 2010", + "/zzz Tracy Pictures 2010/February 2010/February 13 2010", + "/zzz Tracy Pictures 2010/February 2010/February 14 2010", + "/zzz Tracy Pictures 2010/February 2010/February 19 2010", + "/zzz Tracy Pictures 2010/February 2010/February 28 2010", + "/zzz Tracy Pictures 2010/February 2010/February 4 2010", + "/zzz Tracy Pictures 2010/February 2010/February 9 2010", + "/zzz Tracy Pictures 2010/Febuary 2010/Febuary 13 2010", + "/zzz Tracy Pictures 2010/Febuary 2010/Febuary 14 2010", + "/zzz Tracy Pictures 2010/Febuary 2010/Febuary 19 2010", + "/zzz Tracy Pictures 2010/Febuary 2010/Febuary 28 2010", + "/zzz Tracy Pictures 2010/Febuary 2010/Febuary 4 2010", + "/zzz Tracy Pictures 2010/Febuary 2010/Febuary 9 2010", + "/zzz Tracy Pictures 2010/January 2010/January 1 2010", + "/zzz Tracy Pictures 2010/January 2010/January 11 2010", + "/zzz Tracy Pictures 2010/January 2010/January 16 2010", + "/zzz Tracy Pictures 2010/January 2010/January 17 2010", + "/zzz Tracy Pictures 2010/January 2010/January 24 2010", + "/zzz Tracy Pictures 2010/January 2010/January 31 2010", + "/zzz Tracy Pictures 2010/January 2010/January 4 2010", + "/zzz Tracy Pictures 2010/July 29 2010", + "/zzz Tracy Pictures 2010/March 2010/March 1 2010", + "/zzz Tracy Pictures 2010/March 2010/March 11 2010", + "/zzz Tracy Pictures 2010/March 2010/March 23 2010", + "/zzz Tracy Pictures 2010/March 2010/March 3 2010", + "/zzz Tracy Pictures 2010/March 2010/March 4 2010", + "/zzz Tracy Pictures 2010/March 2010/March 5 2010", + "/zzz Tracy Pictures 2010/March 2010/March 9 2010", + "/zzz Tracy Pictures 2010/October 18 2010", + "/zzz Tracy Pictures 2010/October 18 2010/October 18 2010", + "/zzz Tracy Pictures 2011", + "/zzz Tracy Pictures 2011/April 2011", + "/zzz Tracy Pictures 2011/April 2011/April 17 2011", + "/zzz Tracy Pictures 2011/August 2011", + "/zzz Tracy Pictures 2011/August 2011/August 10 2011", + "/zzz Tracy Pictures 2011/August 2011/August 19 2011", + "/zzz Tracy Pictures 2011/August 2011/August 31 2011", + "/zzz Tracy Pictures 2011/August 2011/August 5 2011", + "/zzz Tracy Pictures 2011/December 2011", + "/zzz Tracy Pictures 2011/December 2011/December 16 2011", + "/zzz Tracy Pictures 2011/December 2011/December 22 2011", + "/zzz Tracy Pictures 2011/December 2011/December 24 2011", + "/zzz Tracy Pictures 2011/December 2011/December 25 2011", + "/zzz Tracy Pictures 2011/December 2011/December 4 2011", + "/zzz Tracy Pictures 2011/December 2011/December 8 2011", + "/zzz Tracy Pictures 2011/July 2011", + "/zzz Tracy Pictures 2011/July 2011/July 1 2011", + "/zzz Tracy Pictures 2011/July 2011/July 11 2011", + "/zzz Tracy Pictures 2011/July 2011/July 14 2011", + "/zzz Tracy Pictures 2012/February 2012", + "/zzz Tracy Pictures 2012/February 2012/February 16 2012", + "/zzz Tracy Pictures 2012/February 2012/February 20 2012", + "/zzz Tracy Pictures 2012/February 2012/Febuary 16 2012", + "/zzz Tracy Pictures 2012/February 2012/Febuary 20 2012", + "/zzz Tracy Pictures 2011/July 2011/July 2 2011", + "/zzz Tracy Pictures 2011/July 2011/July 20 2011", + "/zzz Tracy Pictures 2011/July 2011/July 25 2011", + "/zzz Tracy Pictures 2011/July 2011/July 3 2011", + "/zzz Tracy Pictures 2011/July 2011/July 31 2011", + "/zzz Tracy Pictures 2011/July 2011/July 4 2011", + "/zzz Tracy Pictures 2011/July 2011/July 5 2011", + "/zzz Tracy Pictures 2011/June 2011", + "/zzz Tracy Pictures 2011/June 2011/June 28 2011", + "/zzz Tracy Pictures 2011/June 2011/June 29 2011", + "/zzz Tracy Pictures 2011/June 2011/June 30 2011", + "/zzz Tracy Pictures 2011/March 2011", + "/zzz Tracy Pictures 2011/March 2011/March 13 2011", + "/zzz Tracy Pictures 2011/March 2011/March 14 2011", + "/zzz Tracy Pictures 2011/March 2011/March 28 2011", + "/zzz Tracy Pictures 2011/May 2011", + "/zzz Tracy Pictures 2011/November 2011", + "/zzz Tracy Pictures 2011/November 2011/November 1 2011", + "/zzz Tracy Pictures 2011/November 2011/November 12 2011", + "/zzz Tracy Pictures 2011/November 2011/November 13 2011", + "/zzz Tracy Pictures 2011/November 2011/November 19 2011", + "/zzz Tracy Pictures 2011/November 2011/November 21 2011", + "/zzz Tracy Pictures 2011/November 2011/November 24 2011", + "/zzz Tracy Pictures 2011/November 2011/November 9 2011", + "/zzz Tracy Pictures 2011/October 2011", + "/zzz Tracy Pictures 2011/October 2011/October 12 2011", + "/zzz Tracy Pictures 2011/October 2011/October 29 2011", + "/zzz Tracy Pictures 2011/October 2011/October 3 2011", + "/zzz Tracy Pictures 2011/October 2011/OCtober 5 2011", + "/zzz Tracy Pictures 2011/October 2011/October 6 2011", + "/zzz Tracy Pictures 2011/September 2011", + "/zzz Tracy Pictures 2011/September 2011/September 13 2011", + "/zzz Tracy Pictures 2011/September 2011/September 18 2011", + "/zzz Tracy Pictures 2011/September 2011/September 2 2011", + "/zzz Tracy Pictures 2011/September 2011/September 22 2011", + "/zzz Tracy Pictures 2011/September 2011/September 25 2011", + "/zzz Tracy Pictures 2011/September 2011/September 29 2011", + "/zzz Tracy Pictures 2011/September 2011/September 7 2011", + "/zzz Tracy Pictures 2011/September 2011/September 9 2011", + "/zzz Tracy Pictures 2012/April 2012", + "/zzz Tracy Pictures 2012/April 2012/April 17 2012", + "/zzz Tracy Pictures 2012/April 2012/April 18 2012", + "/zzz Tracy Pictures 2012/April 2012/April 3 2012", + "/zzz Tracy Pictures 2012/April 2012/April 7 2012", + "/zzz Tracy Pictures 2012/April 2012/April 9 2012", + "/zzz Tracy Pictures 2012/August 2012", + "/zzz Tracy Pictures 2012/August 2012/August 1 2012", + "/zzz Tracy Pictures 2012/August 2012/August 24 2012", + "/zzz Tracy Pictures 2012/December 2012/December 1 2012", + "/zzz Tracy Pictures 2012/December 2012/December 11 2012", + "/zzz Tracy Pictures 2012/December 2012/December 15 2012", + "/zzz Tracy Pictures 2012/December 2012/December 16 2012", + "/zzz Tracy Pictures 2012/December 2012/December 18 2012", + "/zzz Tracy Pictures 2012/December 2012/December 2 2012", + "/zzz Tracy Pictures 2012/December 2012/December 24 2012", + "/zzz Tracy Pictures 2012/December 2012/December 25 2012", + "/zzz Tracy Pictures 2012/December 2012/December 7 2012", + "/zzz Tracy Pictures 2012/December 2012/December 8 2012", + "/zzz Tracy Pictures 2012/December 2012/December 9 2012", + "/zzz Tracy Pictures 2012/Feburay 2012", + "/zzz Tracy Pictures 2012/Feburay 2012/February 16 2012", + "/zzz Tracy Pictures 2012/Feburay 2012/February 20 2012", + "/zzz Tracy Pictures 2012/Feburay 2012/Febuary 16 2012", + "/zzz Tracy Pictures 2012/Feburay 2012/Febuary 20 2012", + "/zzz Tracy Pictures 2012/January 2012", + "/zzz Tracy Pictures 2012/January 2012/January 20 2012", + "/zzz Tracy Pictures 2012/July 2012", + "/zzz Tracy Pictures 2012/July 2012/July 12 2012", + "/zzz Tracy Pictures 2012/July 2012/July 21 2012", + "/zzz Tracy Pictures 2012/July 2012/July 26 2012", + "/zzz Tracy Pictures 2012/June 2012", + "/zzz Tracy Pictures 2012/June 2012/June 17 2012", + "/zzz Tracy Pictures 2012/June 2012/June 18 2012", + "/zzz Tracy Pictures 2012/June 2012/June 2 2012", + "/zzz Tracy Pictures 2012/June 2012/June 26 2012", + "/zzz Tracy Pictures 2012/June 2012/June 6 2012", + "/zzz Tracy Pictures 2012/March 2012", + "/zzz Tracy Pictures 2012/March 2012/March 14 2012", + "/zzz Tracy Pictures 2012/March 2012/March 17 2012", + "/zzz Tracy Pictures 2012/March 2012/March 20 2012", + "/zzz Tracy Pictures 2012/March 2012/March 30 2012", + "/zzz Tracy Pictures 2012/March 2012/March 6 2012", + "/zzz Tracy Pictures 2012/March 2012/March 8 2012", + "/zzz Tracy Pictures 2012/May 2012", + "/zzz Tracy Pictures 2012/May 2012/May 11 2012", + "/zzz Tracy Pictures 2012/May 2012/May 12 2012", + "/zzz Tracy Pictures 2012/May 2012/May 15 2012", + "/zzz Tracy Pictures 2012/May 2012/May 17 2012", + "/zzz Tracy Pictures 2012/May 2012/May 18 2012", + "/zzz Tracy Pictures 2012/May 2012/May 21 2012", + "/zzz Tracy Pictures 2012/May 2012/May 22 2012", + "/zzz Tracy Pictures 2012/May 2012/May 24 2012", + "/zzz Tracy Pictures 2012/May 2012/May 26 2012", + "/zzz Tracy Pictures 2012/November 2012", + "/zzz Tracy Pictures 2012/November 2012/November 15 2012", + "/zzz Tracy Pictures 2012/November 2012/November 17 2012", + "/zzz Tracy Pictures 2012/November 2012/November 24 2012", + "/zzz Tracy Pictures 2012/November 2012/November 25 2012", + "/zzz Tracy Pictures 2012/November 2012/November 28 2012", + "/zzz Tracy Pictures 2012/November 2012/November 3 2012", + "/zzz Tracy Pictures 2012/October 2012", + "/zzz Tracy Pictures 2012/October 2012/October 17 2012", + "/zzz Tracy Pictures 2012/October 2012/October 24 2012", + "/zzz Tracy Pictures 2012/October 2012/October 27 2012", + "/zzz Tracy Pictures 2012/October 2012/October 28 2012", + "/zzz Tracy Pictures 2012/October 2012/October 30 2012", + "/zzz Tracy Pictures 2012/October 2012/October 31 2012", + "/zzz Tracy Pictures 2012/October 2012/October 7 2012", + "/zzz Tracy Pictures 2012/Sebtember 2012/September 11 2012", + "/zzz Tracy Pictures 2012/Sebtember 2012/September 12 2012", + "/zzz Tracy Pictures 2012/Sebtember 2012/September 16 2012", + "/zzz Tracy Pictures 2012/Sebtember 2012/September 19 2012", + "/zzz Tracy Pictures 2012/Sebtember 2012/September 28 2012", + "/zzz Tracy Pictures 2012/Sebtember 2012/September 29 2012", + "/zzz Tracy Pictures 2012/Sebtember 2012/September 30 2012", + "/zzz Tracy Pictures 2012/September 2012/September 11 2012", + "/zzz Tracy Pictures 2012/September 2012/September 12 2012", + "/zzz Tracy Pictures 2012/September 2012/September 16 2012", + "/zzz Tracy Pictures 2012/September 2012/September 19 2012", + "/zzz Tracy Pictures 2012/September 2012/September 28 2012", + "/zzz Tracy Pictures 2012/September 2012/September 29 2012", + "/zzz Tracy Pictures 2012/September 2012/September 30 2012", + "/zzz Tracy Pictures 2013/April 2013/April 11 2013", + "/zzz Tracy Pictures 2013/April 2013/April 17 2013", + "/zzz Tracy Pictures 2013/April 2013/April 19 2013", + "/zzz Tracy Pictures 2013/April 2013/April 21 2013", + "/zzz Tracy Pictures 2013/April 2013/April 25 2013", + "/zzz Tracy Pictures 2013/April 2013/April 28 2013", + "/zzz Tracy Pictures 2013/August 2013/August 14 2013", + "/zzz Tracy Pictures 2013/August 2013/August 18 2013", + "/zzz Tracy Pictures 2013/August 2013/August 19 2013", + "/zzz Tracy Pictures 2013/August 2013/August 2 2013", + "/zzz Tracy Pictures 2013/December 2013", + "/zzz Tracy Pictures 2013/December 2013/December 10 2013", + "/zzz Tracy Pictures 2013/December 2013/December 23 2013", + "/zzz Tracy Pictures 2013/December 2013/December 24 2013", + "/zzz Tracy Pictures 2013/December 2013/December 9 2013", + "/zzz Tracy Pictures 2013/February 2013", + "/zzz Tracy Pictures 2013/February 2013/February 23 2013", + "/zzz Tracy Pictures 2013/February 2013/February 24 2013", + "/zzz Tracy Pictures 2013/February 2013/February 5 2013", + "/zzz Tracy Pictures 2013/February 2013/February 7 2013", + "/zzz Tracy Pictures 2013/Febuary 2013", + "/zzz Tracy Pictures 2013/Febuary 2013/Febuary 23 2013", + "/zzz Tracy Pictures 2013/Febuary 2013/Febuary 24 2013", + "/zzz Tracy Pictures 2013/Febuary 2013/Febuary 5 2013", + "/zzz Tracy Pictures 2013/Febuary 2013/Febuary 7 2013", + "/zzz Tracy Pictures 2013/January 2013/January 20 2013", + "/zzz Tracy Pictures 2013/January 2013/January 25 2013", + "/zzz Tracy Pictures 2013/July 2013", + "/zzz Tracy Pictures 2013/July 2013/July 13 2013", + "/zzz Tracy Pictures 2013/July 2013/July 14 2013", + "/zzz Tracy Pictures 2013/July 2013/July 3 2013", + "/zzz Tracy Pictures 2013/July 2013/July 6 2013", + "/zzz Tracy Pictures 2013/July 3 2013", + "/zzz Tracy Pictures 2013/June 2013", + "/zzz Tracy Pictures 2013/June 2013/June 1 2013", + "/zzz Tracy Pictures 2013/June 2013/June 10 2013", + "/zzz Tracy Pictures 2013/June 2013/June 15 2013", + "/zzz Tracy Pictures 2013/June 2013/June 16 2013", + "/zzz Tracy Pictures 2013/June 2013/June 18 2013", + "/zzz Tracy Pictures 2013/June 2013/June 19 2013", + "/zzz Tracy Pictures 2013/June 2013/June 26 2013", + "/zzz Tracy Pictures 2013/June 2013/June 28 2013", + "/zzz Tracy Pictures 2013/June 2013/June 3 2013", + "/zzz Tracy Pictures 2013/June 2013/June 9 2013", + "/zzz Tracy Pictures 2013/March 2013", + "/zzz Tracy Pictures 2013/March 2013/March 16 2013", + "/zzz Tracy Pictures 2013/March 2013/March 19 2013", + "/zzz Tracy Pictures 2013/March 2013/March 28 2013", + "/zzz Tracy Pictures 2013/March 2013/March 30 2013", + "/zzz Tracy Pictures 2013/March 2013/March 31 2013", + "/zzz Tracy Pictures 2013/May 2013/May 1 2013", + "/zzz Tracy Pictures 2013/May 2013/May 12 2013", + "/zzz Tracy Pictures 2013/May 2013/May 21 2013", + "/zzz Tracy Pictures 2013/May 2013/May 29 2013", + "/zzz Tracy Pictures 2013/May 2013/May 30 2013", + "/zzz Tracy Pictures 2013/May 2013/May 31 2013", + "/zzz Tracy Pictures 2013/May 2013/May 8 2013", + "/zzz Tracy Pictures 2013/May 2013/May 9 2014", + "/zzz Tracy Pictures 2013/November 2013", + "/zzz Tracy Pictures 2013/November 2013/November 15 2013", + "/zzz Tracy Pictures 2013/November 2013/November 16 2013", + "/zzz Tracy Pictures 2013/November 2013/November 20 2013", + "/zzz Tracy Pictures 2013/November 2013/November 22 2013", + "/zzz Tracy Pictures 2013/November 2013/November 28 2013", + "/zzz Tracy Pictures 2013/October 2013", + "/zzz Tracy Pictures 2013/October 2013/October 12 2013", + "/zzz Tracy Pictures 2013/October 2013/October 2 2013", + "/zzz Tracy Pictures 2013/October 2013/October 20 2013", + "/zzz Tracy Pictures 2013/October 2013/October 3 2013", + "/zzz Tracy Pictures 2013/October 2013/OCtober 31 2013", + "/zzz Tracy Pictures 2013/September 2013", + "/zzz Tracy Pictures 2013/September 2013/September 1 2013", + "/zzz Tracy Pictures 2013/September 2013/September 18 2013", + "/zzz Tracy Pictures 2013/September 2013/September 27 2013", + "/zzz Tracy Pictures 2014/April 2014", + "/zzz Tracy Pictures 2014/April 2014/April 17 2014", + "/zzz Tracy Pictures 2014/April 2014/April 27 2014", + "/zzz Tracy Pictures 2014/April 2014/April 30 2014", + "/zzz Tracy Pictures 2014/April 2014/April 9 2014", + "/zzz Tracy Pictures 2014/December 2014/December 19 2014", + "/zzz Tracy Pictures 2014/December 2014/December 20 2014", + "/zzz Tracy Pictures 2014/December 2014/December 24 2014", + "/zzz Tracy Pictures 2014/December 2014/December 25 2014", + "/zzz Tracy Pictures 2014/February 2014", + "/zzz Tracy Pictures 2014/February 2014/February 27 2014", + "/zzz Tracy Pictures 2014/February 2014/February 8 2014", + "/zzz Tracy Pictures 2014/Febuary 2014", + "/zzz Tracy Pictures 2014/Febuary 2014/Febuary 27 2014", + "/zzz Tracy Pictures 2014/Febuary 2014/Febuary 8 2014", + "/zzz Tracy Pictures 2014/January 2014", + "/zzz Tracy Pictures 2014/January 2014/January 20 2014", + "/zzz Tracy Pictures 2014/January 2014/January 31 2014", + "/zzz Tracy Pictures 2014/January 2014/January 4 2014", + "/zzz Tracy Pictures 2014/July 2014", + "/zzz Tracy Pictures 2014/July 2014/July 19 2014", + "/zzz Tracy Pictures 2014/June 2014", + "/zzz Tracy Pictures 2014/June 2014/June 17 2014", + "/zzz Tracy Pictures 2014/June 2014/June 20 2014", + "/zzz Tracy Pictures 2014/June 2014/June 21 2014", + "/zzz Tracy Pictures 2014/March 2014", + "/zzz Tracy Pictures 2014/May 2014/May 15 2014", + "/zzz Tracy Pictures 2014/May 2014/May 17 2014", + "/zzz Tracy Pictures 2014/May 2014/May 22 2014", + "/zzz Tracy Pictures 2014/May 2014/May 23 2014", + "/zzz Tracy Pictures 2014/May 2014/May 24 2014", + "/zzz Tracy Pictures 2014/May 2014/May 25 2014", + "/zzz Tracy Pictures 2014/May 2014/May 26 2014", + "/zzz Tracy Pictures 2014/May 2014/May 3 2012 j bday", + "/zzz Tracy Pictures 2014/May 2014/May 6 2014", + "/zzz Tracy Pictures 2014/May 2014/May 9 2014", + "/zzz Tracy Pictures 2014/November 2014", + "/zzz Tracy Pictures 2014/November 2014/November 2 2014", + "/zzz Tracy Pictures 2014/November 2014/November 20 2014", + "/zzz Tracy Pictures 2014/November 2014/November 23 2014", + "/zzz Tracy Pictures 2014/November 2014/November 24 2014", + "/zzz Tracy Pictures 2014/November 2014/November 27 2014", + "/zzz Tracy Pictures 2014/November 2014/November 29 2014", + "/zzz Tracy Pictures 2014/November 2014/November 3 2014", + "/zzz Tracy Pictures 2014/October 2014", + "/zzz Tracy Pictures 2014/October 2014/October 11 2014", + "/zzz Tracy Pictures 2014/October 2014/October 17 2014", + "/zzz Tracy Pictures 2014/October 2014/October 18 2014", + "/zzz Tracy Pictures 2014/October 2014/October 24 2014", + "/zzz Tracy Pictures 2014/October 2014/October 26 2014", + "/zzz Tracy Pictures 2014/October 2014/October 30 2014", + "/zzz Tracy Pictures 2014/October 2014/OCtober 31 2014", + "/zzz Tracy Pictures 2014/October 2014/October 8 2014", + "/zzz Tracy Pictures 2014/September 2014", + "/zzz Tracy Pictures 2014/September 2014/September 12 2014", + "/zzz Tracy Pictures 2014/September 2014/September 20 2014", + "/zzz Tracy Pictures 2015/Copied from user Tracy/2015-01-01" + ] + } + } +} \ No newline at end of file diff --git a/Date-Group/.vscode/format-report.json b/Date-Group/.vscode/format-report.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/Date-Group/.vscode/format-report.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/Date-Group/.vscode/launch.json b/Date-Group/.vscode/launch.json new file mode 100644 index 0000000..0368280 --- /dev/null +++ b/Date-Group/.vscode/launch.json @@ -0,0 +1,30 @@ +{ + "version": "0.2.0", + "configurations": [ + { + // Use IntelliSense to find out which attributes exist for C# debugging + // Use hover for the description of the existing attributes + // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md + "name": ".NET Core Launch (console)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + // If you have changed target frameworks, make sure to update the program path. + "program": "${workspaceFolder}/bin/Debug/net6.0/win-x64/Date-Group.dll", + "args": [], + "env": { + "ASPNETCORE_ENVIRONMENT": "Development", + }, + "cwd": "${workspaceFolder}", + // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console + "console": "externalTerminal", + "stopAtEntry": false + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach", + "processName": "Date-Group" + } + ] +} \ No newline at end of file diff --git a/Date-Group/.vscode/settings.json b/Date-Group/.vscode/settings.json new file mode 100644 index 0000000..09ac856 --- /dev/null +++ b/Date-Group/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "cSpell.words": [ + "Barrick", + "Beichler", + "Bohdi", + "Dlib", + "Phares", + "Serilog", + "Vericruz" + ] +} \ No newline at end of file diff --git a/Date-Group/.vscode/tasks.json b/Date-Group/.vscode/tasks.json new file mode 100644 index 0000000..77966c4 --- /dev/null +++ b/Date-Group/.vscode/tasks.json @@ -0,0 +1,42 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/Date-Group.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "publish", + "command": "dotnet", + "type": "process", + "args": [ + "publish", + "${workspaceFolder}/Date-Group.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "watch", + "command": "dotnet", + "type": "process", + "args": [ + "watch", + "run", + "${workspaceFolder}/Date-Group.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/Date-Group/Date-Group.csproj b/Date-Group/Date-Group.csproj new file mode 100644 index 0000000..2b69460 --- /dev/null +++ b/Date-Group/Date-Group.csproj @@ -0,0 +1,63 @@ + + + enable + 10.0 + enable + Exe + win-x64 + net6.0 + + + Phares.View.by.Distance.Date.Group + false + 5.0.402.104 + Mike Phares + Phares + true + snupkg + + + true + true + true + + + Windows + + + OSX + + + Linux + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Always + + + \ No newline at end of file diff --git a/Date-Group/DateGroup.cs b/Date-Group/DateGroup.cs new file mode 100644 index 0000000..3ce0df8 --- /dev/null +++ b/Date-Group/DateGroup.cs @@ -0,0 +1,426 @@ +using Microsoft.Extensions.Configuration; +using Phares.Shared; +using System.Globalization; +using System.Text; +using View_by_Distance.Date.Group.Models; +using View_by_Distance.Property.Models; +using View_by_Distance.Shared.Models.Methods; + +namespace View_by_Distance.Date.Group; + +public class DateGroup +{ + + private readonly Serilog.ILogger? _Log; + private readonly AppSettings _AppSettings; + private readonly List _Exceptions; + private readonly IsEnvironment _IsEnvironment; + private readonly Models.Configuration _Configuration; + private readonly List> _FileKeyValuePairs; + private readonly Dictionary>> _FilePropertiesKeyValuePairs; + + public DateGroup(List args, IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, AppSettings appSettings, string workingDirectory, bool isSilent, IConsole console) + { + if (isSilent) + { } + if (args is null) + { } + if (console is null) + { } + _AppSettings = appSettings; + if (appSettings.MaxDegreeOfParallelism is null) + throw new Exception($"{nameof(appSettings.MaxDegreeOfParallelism)} is null!"); + _IsEnvironment = isEnvironment; + _Exceptions = new List(); + _Log = Serilog.Log.ForContext(); + _FileKeyValuePairs = new List>(); + _FilePropertiesKeyValuePairs = new Dictionary>>(); + Property.Models.Configuration propertyConfiguration = Property.Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory); + Property.Models.Configuration.Verify(propertyConfiguration); + Models.Configuration configuration = Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory, propertyConfiguration); + Verify(configuration); + _Configuration = configuration; + if (configuration.ByHash is null) + throw new Exception($"{nameof(configuration.ByHash)} is null!"); + if (propertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass is null) + throw new Exception($"{nameof(propertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass)} is null!"); + if (propertyConfiguration.PopulatePropertyId is null) + throw new Exception($"{nameof(propertyConfiguration.PopulatePropertyId)} is null!"); + if (!_IsEnvironment.Development) + throw new Exception("This program only allows development environments!"); + string searchPattern = "*"; + long ticks = DateTime.Now.Ticks; + List topDirectories = new(); + PropertyLogic propertyLogic = GetPropertyLogic(); + string[] dbFiles = Directory.GetFiles(propertyConfiguration.RootDirectory, "*.db", SearchOption.AllDirectories); + foreach (string dbFile in dbFiles) + File.Delete(dbFile); + for (int i = 1; i < 10; i++) + _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(propertyConfiguration.RootDirectory); + List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> groupCollection = Property.Models.Stateless.A_Property.GetGroupCollection(propertyConfiguration.RootDirectory, searchPattern, topDirectories, propertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass.Value, reverse: false); + if (appSettings.MaxDegreeOfParallelism.Value < 2) + ticks = LogDelta(ticks, nameof(Property.Models.Stateless.A_Property.GetGroupCollection)); + List groupResultsCollection = new(); + if (!propertyConfiguration.PopulatePropertyId.Value || !configuration.ByHash.Value) + groupResultsCollection = propertyLogic.GetParallelWork(propertyConfiguration, topDirectories, groupCollection, firstPass: true, filterOnFirstPass: true); + else + { + _Exceptions.AddRange(propertyLogic.DoWork(propertyConfiguration, topDirectories, groupCollection, firstPass: true)); + string message = $"There were {_Exceptions.Count} exception(s) thrown! {Environment.NewLine}{string.Join(Environment.NewLine, _Exceptions)}"; + _Log.Information(message); + if (_Exceptions.Count != 0) + throw new Exception(message); + if (appSettings.MaxDegreeOfParallelism.Value < 2) + ticks = LogDelta(ticks, nameof(PropertyLogic.DoWork)); + topDirectories.Clear(); + groupCollection = Property.Models.Stateless.A_Property.GetGroupCollection(propertyConfiguration.RootDirectory, searchPattern, topDirectories, propertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass.Value, reverse: false); + if (appSettings.MaxDegreeOfParallelism.Value < 2) + ticks = LogDelta(ticks, nameof(Property.Models.Stateless.A_Property.GetGroupCollection)); + groupResultsCollection = propertyLogic.GetParallelWork(propertyConfiguration, topDirectories, groupCollection, firstPass: false, filterOnFirstPass: true); + } + MoveFiles(topDirectories, groupResultsCollection); + } + + private static void Verify(Models.Configuration configuration) + { + if (configuration.ByDay is null) + throw new Exception($"{nameof(configuration.ByDay)} is null!"); + if (configuration.ByHash is null) + throw new Exception($"{nameof(configuration.ByHash)} is null!"); + if (configuration.BySeason is null) + throw new Exception($"{nameof(configuration.BySeason)} is null!"); + if (configuration.ByWeek is null) + throw new Exception($"{nameof(configuration.ByWeek)} is null!"); + if (!configuration.ByDay.Value && !configuration.ByWeek.Value && !configuration.BySeason.Value && !configuration.ByHash.Value) + throw new Exception("Change configuration!"); + if (configuration.KeepFullPath is null) + throw new Exception($"{nameof(configuration.KeepFullPath)} is null!"); + if (configuration?.PropertyConfiguration?.PopulatePropertyId is null) + throw new Exception($"{nameof(configuration.PropertyConfiguration.PopulatePropertyId)} must be set!"); + if (configuration.PropertyConfiguration.PopulatePropertyId.Value && !configuration.ByHash.Value) + throw new Exception("Change configuration!"); + if (!configuration.PropertyConfiguration.PopulatePropertyId.Value && configuration.ByHash.Value) + throw new Exception("Change configuration!"); + if (configuration.ByDay.Value && configuration.ByWeek.Value && configuration.BySeason.Value && configuration.ByHash.Value) + throw new Exception("Change configuration!"); + } + + private static bool WriteAllText(string path, string contents, bool compareBeforeWrite) + { + bool result; + string text; + if (!compareBeforeWrite) + result = true; + else + { + if (!File.Exists(path)) + text = string.Empty; + else + text = File.ReadAllText(path); + result = text != contents; + } + if (result) + { + if (path.Contains("()")) + File.WriteAllText(path, contents); + else if (path.Contains("{}") && !path.EndsWith(".json")) + File.WriteAllText(path, contents); + else if (path.Contains("[]") && !path.EndsWith(".json")) + File.WriteAllText(path, contents); + else if (path.Contains("{}") && path.EndsWith(".json") && contents[0] == '{') + File.WriteAllText(path, contents); + else if (path.Contains("[]") && path.EndsWith(".json") && contents[0] == '[') + File.WriteAllText(path, contents); + else + File.WriteAllText(path, contents); + } + return result; + } + + private long LogDelta(long ticks, string methodName) + { + long result; + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + double delta = new TimeSpan(DateTime.Now.Ticks - ticks).TotalMilliseconds; + _Log.Debug($"{methodName} took {Math.Floor(delta)} millisecond(s)"); + result = DateTime.Now.Ticks; + return result; + } + + private List<(string Source, string[] Destination)> GetMoveFileCollection(string destinationDirectory, string topDirectory, Property.Models.Group group) + { + List<(string Source, string[] Destination)> results = new(); + if (_Configuration.ByDay is null) + throw new Exception($"{nameof(_Configuration.ByDay)} is null!"); + if (_Configuration.ByHash is null) + throw new Exception($"{nameof(_Configuration.ByHash)} is null!"); + if (_Configuration.BySeason is null) + throw new Exception($"{nameof(_Configuration.BySeason)} is null!"); + if (_Configuration.ByWeek is null) + throw new Exception($"{nameof(_Configuration.ByWeek)} is null!"); + if (_Configuration.KeepFullPath is null) + throw new Exception($"{nameof(_Configuration.KeepFullPath)} is null!"); + char flag; + string day; + int season; + string year; + string month; + string? check; + string fileName; + string? pathRoot; + string seasonName; + string weekOfYear; + string? directory; + string seasonValue; + A_Property? property; + string directoryName; + bool? propertyWrongYear; + string topDirectoryName; + string[]? matches = null; + string[] directorySegments; + DateTime? minimumDateTime = null; + List destinationCollection; + string filteredSourceDirectoryFile; + List directoryNames = new(); + List topDirectorySegments = new(); + StringBuilder destinationDirectoryName = new(); + Calendar calendar = new CultureInfo("en-US").Calendar; + for (int z = 1; z < 3; z++) + { + if (z == 1) + { + check = Path.Combine(destinationDirectory, "."); + pathRoot = Path.GetPathRoot(destinationDirectory); + } + else if (z == 2) + { + check = Path.Combine(topDirectory, "."); + pathRoot = Path.GetPathRoot(topDirectory); + } + else + throw new Exception(); + if (string.IsNullOrEmpty(pathRoot)) + continue; + for (int i = 0; i < int.MaxValue; i++) + { + check = Path.GetDirectoryName(check); + if (string.IsNullOrEmpty(check) || check == pathRoot) + break; + directoryName = Path.GetFileName(check); + directorySegments = directoryName.Split(' '); + topDirectorySegments.AddRange(directorySegments); + (_, matches) = Property.Models.Stateless.A_Property.IsWrongYear(directorySegments, string.Empty); + if (matches.Any()) + break; + } + if (matches is not null && matches.Any()) + break; + } + if (matches is null) + matches = Array.Empty(); + for (int i = 0; i < group.FilteredSourceDirectoryFiles.Length; i++) + { + destinationCollection = new(); + directoryNames.Clear(); + _ = destinationDirectoryName.Clear(); + property = group.PropertyCollection[i]; + if (property is null) + continue; + filteredSourceDirectoryFile = group.FilteredSourceDirectoryFiles[i]; + minimumDateTime = Property.Models.Stateless.A_Property.GetMinimumDateTime(property); + directory = Path.GetDirectoryName(filteredSourceDirectoryFile); + if (string.IsNullOrEmpty(directory)) + continue; + day = minimumDateTime.Value.ToString("MM-dd"); + month = minimumDateTime.Value.ToString("MMMM"); + (propertyWrongYear, _) = property.IsWrongYear(filteredSourceDirectoryFile, minimumDateTime); + if (propertyWrongYear is null) + flag = '#'; + else + { + if (propertyWrongYear.Value) + flag = '~'; + else + { + if (property.DateTimeOriginal.HasValue && minimumDateTime.Value.DayOfYear != property.DateTimeOriginal.Value.DayOfYear && Math.Abs(new TimeSpan(minimumDateTime.Value.Ticks - property.DateTimeOriginal.Value.Ticks).TotalHours) > 8) + flag = '^'; + else + flag = '='; + } + } + (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(minimumDateTime.Value.DayOfYear); + if ((from l in topDirectorySegments where l == "Christmas" select true).Any()) + seasonValue = string.Empty; + else + seasonValue = $".{season}"; + if (propertyWrongYear is null || !propertyWrongYear.Value) + year = $"{flag}{minimumDateTime.Value:yyyy}{seasonValue}"; + else + { + if (matches[0][0] != '~') + year = $"{flag}{matches[0].Split('.')[0]}{seasonValue}"; + else + year = $"{flag}{matches[0][1..].Split('.')[0]}{seasonValue}"; + } + topDirectoryName = Path.GetFileName(topDirectory); + weekOfYear = calendar.GetWeekOfYear(minimumDateTime.Value, CalendarWeekRule.FirstDay, DayOfWeek.Sunday).ToString("00"); + if (_Configuration.ByHash.Value) + directoryNames.Add($"{year} {seasonName}"); + else if (_Configuration.BySeason.Value && topDirectoryName.Length == 1 && topDirectoryName[0] == '_') + directoryNames.Add($"{year} {seasonName}"); + else + { + if (!_Configuration.KeepFullPath.Value) + { + _ = destinationDirectoryName.Append(topDirectoryName); + if (_Configuration.BySeason.Value) + directoryNames.AddRange(new string[] { $"{destinationDirectoryName} {year}", $"{year} {seasonName}" }); + else if (_Configuration.ByDay.Value) + directoryNames.AddRange(new string[] { $"{destinationDirectoryName} {year}", $"{weekOfYear}) {year}-{day}" }); + else if (_Configuration.ByWeek.Value) + directoryNames.AddRange(new string[] { $"{destinationDirectoryName} {year}", $"{weekOfYear}) {year} {month}" }); + else + throw new Exception(); + } + else + { + foreach (string sourceDirectoryNameSegment in topDirectorySegments) + { + if (matches.Contains(sourceDirectoryNameSegment)) + _ = destinationDirectoryName.Append(year); + else + _ = destinationDirectoryName.Append(sourceDirectoryNameSegment); + } + if (_Configuration.BySeason.Value) + directoryNames.Add($"{year} {seasonName}"); + else if (_Configuration.ByDay.Value) + directoryNames.Add($"{weekOfYear}) {year} {day}"); + else if (_Configuration.ByWeek.Value) + directoryNames.Add($"{weekOfYear}) {month} {year}"); + else + throw new Exception(); + } + } + if (!_Configuration.ByHash.Value || property.Id is null) + fileName = Path.GetFileName(filteredSourceDirectoryFile); + else + fileName = $"{property.Id.Value}{Path.GetExtension(filteredSourceDirectoryFile).ToLower()}"; + destinationCollection.Add(destinationDirectory); + destinationCollection.AddRange(directoryNames); + destinationCollection.Add(fileName); + results.Add(new(filteredSourceDirectoryFile, destinationCollection.ToArray())); + } + return results; + } + + private PropertyLogic GetPropertyLogic() + { + PropertyLogic result; + + string[] verifyToSeason = Array.Empty(); + + if (_AppSettings.MaxDegreeOfParallelism is null) + throw new Exception($"{nameof(_AppSettings.MaxDegreeOfParallelism)} is null!"); + if (_Configuration?.PropertyConfiguration is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + result = new(_AppSettings.MaxDegreeOfParallelism.Value, _Configuration.PropertyConfiguration, verifyToSeason); + return result; + } + + private List<(string Source, string[] Destination)> GetFileMoveCollectionAll(List topDirectories, List groupCollection) + { + List<(string Source, string[] Destination)> results = new(); + if (_Configuration.KeepFullPath is null) + throw new Exception($"{nameof(_Configuration.KeepFullPath)} is null!"); + if (_Configuration?.PropertyConfiguration is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + string? topDirectory; + string? checkDirectory; + string sourceDirectory; + string destinationDirectory; + string destinationRoot = Property.Models.Stateless.IResult.GetResultsGroupDirectory(_Configuration.PropertyConfiguration, "Z) Moved"); + List<(string Source, string[] Destination)> fileMoveCollectionDirectory; + foreach (Property.Models.Group group in groupCollection) + { + sourceDirectory = group.SourceDirectory; + if (!_Configuration.KeepFullPath.Value) + destinationDirectory = destinationRoot; + else + destinationDirectory = string.Concat(destinationRoot, sourceDirectory[_Configuration.PropertyConfiguration.RootDirectory.Length..]); + checkDirectory = Path.GetFullPath(sourceDirectory); + for (int z = 0; z < int.MaxValue; z++) + { + if (checkDirectory == _Configuration.PropertyConfiguration.RootDirectory || topDirectories.Contains(checkDirectory)) + break; + checkDirectory = Path.GetDirectoryName(checkDirectory); + if (string.IsNullOrEmpty(checkDirectory)) + break; + } + if (string.IsNullOrEmpty(checkDirectory)) + continue; + topDirectory = checkDirectory; + fileMoveCollectionDirectory = GetMoveFileCollection(destinationDirectory, topDirectory, group); + results.AddRange(fileMoveCollectionDirectory); + } + return results; + } + + private void MoveFiles(List topDirectories, List groupCollection) + { + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + if (_Configuration?.PropertyConfiguration is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + string directoryName; + List distinct = new(); + List<(string Source, string[] Destination)> fileMoveCollectionAll = GetFileMoveCollectionAll(topDirectories, groupCollection); + foreach ((string source, string[] destination) in fileMoveCollectionAll) + { + directoryName = Path.Combine(destination.Take(destination.Length - 1).ToArray()); + if (distinct.Contains(directoryName)) + continue; + distinct.Add(directoryName); + if (!Directory.Exists(directoryName)) + _ = Directory.CreateDirectory(directoryName); + } + _Log.Information("Ready to move files?"); + for (int y = 0; y < int.MaxValue; y++) + { + _Log.Information("Press \"Y\" key to move files back or close console to not move files"); + if (Console.ReadKey().Key == ConsoleKey.Y) + break; + } + _Log.Information(". . ."); + int moved = 0; + string fullFileName; + foreach ((string source, string[] destination) in fileMoveCollectionAll) + { + fullFileName = Path.Combine(destination); + if (File.Exists(fullFileName)) + continue; + File.Move(source, fullFileName); + moved += 1; + } + _Log.Information($"{moved} file(s) moved"); + for (int y = 0; y < int.MaxValue; y++) + { + _Log.Information("Press \"Y\" key to move files back or close console to leave them moved"); + if (Console.ReadKey().Key == ConsoleKey.Y) + break; + } + _Log.Information(". . ."); + foreach ((string source, string[] destination) in fileMoveCollectionAll) + { + fullFileName = Path.Combine(destination); + if (File.Exists(source)) + continue; + File.Move(fullFileName, source); + moved += 1; + } + _Log.Information($"Done moving back {moved} file(s)"); + for (int i = 1; i < 10; i++) + _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(_Configuration.PropertyConfiguration.RootDirectory); + } + +} \ No newline at end of file diff --git a/Date-Group/Models/AppSettings.cs b/Date-Group/Models/AppSettings.cs new file mode 100644 index 0000000..998922e --- /dev/null +++ b/Date-Group/Models/AppSettings.cs @@ -0,0 +1,35 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Date.Group.Models; + +public class AppSettings +{ + + protected string _Company; + protected string _WorkingDirectoryName; + protected int? _MaxDegreeOfParallelism; + public string Company => _Company; + public string WorkingDirectoryName => _WorkingDirectoryName; + public int? MaxDegreeOfParallelism => _MaxDegreeOfParallelism; + + // public AppSettings() + // { + + // } + + [JsonConstructor] + public AppSettings(string company, string workingDirectoryName, int? maxDegreeOfParallelism) + { + _Company = company; + _WorkingDirectoryName = workingDirectoryName; + _MaxDegreeOfParallelism = maxDegreeOfParallelism; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/Date-Group/Models/Binder/AppSettings.cs b/Date-Group/Models/Binder/AppSettings.cs new file mode 100644 index 0000000..01cf4a1 --- /dev/null +++ b/Date-Group/Models/Binder/AppSettings.cs @@ -0,0 +1,26 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.Json; + +namespace View_by_Distance.Date.Group.Models.Binder; + +public class AppSettings +{ + + [Display(Name = "Company"), Required] public string Company { get; set; } + [Display(Name = "Working Directory Name"), Required] public string WorkingDirectoryName { get; set; } + [Display(Name = "Max Degree Of Parallelism"), Required] public int? MaxDegreeOfParallelism { get; set; } + + public AppSettings() + { + Company = string.Empty; + WorkingDirectoryName = string.Empty; + MaxDegreeOfParallelism = -1; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/Date-Group/Models/Binder/Configuration.cs b/Date-Group/Models/Binder/Configuration.cs new file mode 100644 index 0000000..0f759e0 --- /dev/null +++ b/Date-Group/Models/Binder/Configuration.cs @@ -0,0 +1,30 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.Json; + +namespace View_by_Distance.Date.Group.Models.Binder; + +public class Configuration +{ + [Display(Name = "By Date"), Required] public bool? ByDay { get; set; } + [Display(Name = "By Hash"), Required] public bool? ByHash { get; set; } + [Display(Name = "By Season"), Required] public bool? BySeason { get; set; } + [Display(Name = "By Week"), Required] public bool? ByWeek { get; set; } + [Display(Name = "Ignore Subdirectories for Rename"), Required] public bool? KeepFullPath { get; set; } + [Display(Name = "Property Configuration"), Required] public Property.Models.Configuration? PropertyConfiguration { get; set; } + + public Configuration() + { + ByDay = null; + ByHash = null; + BySeason = null; + ByWeek = null; + KeepFullPath = null; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/Date-Group/Models/Configuration.cs b/Date-Group/Models/Configuration.cs new file mode 100644 index 0000000..9623679 --- /dev/null +++ b/Date-Group/Models/Configuration.cs @@ -0,0 +1,43 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Date.Group.Models; + +public class Configuration +{ + + protected readonly bool? _ByDay; + protected readonly bool? _ByHash; + protected readonly bool? _BySeason; + protected readonly bool? _ByWeek; + protected readonly bool? _KeepFullPath; + protected Property.Models.Configuration? _PropertyConfiguration; + public bool? ByDay => _ByDay; + public bool? ByHash => _ByHash; + public bool? BySeason => _BySeason; + public bool? ByWeek => _ByWeek; + public bool? KeepFullPath => _KeepFullPath; + public Property.Models.Configuration? PropertyConfiguration => _PropertyConfiguration; + + [JsonConstructor] + public Configuration(bool? byDay, bool? byHash, bool? bySeason, bool? byWeek, bool? keepFullPath, Property.Models.Configuration? propertyConfiguration) + { + _ByDay = byDay; + _ByHash = byHash; + _BySeason = bySeason; + _ByWeek = byWeek; + _KeepFullPath = keepFullPath; + _PropertyConfiguration = propertyConfiguration; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + + public void Set(Property.Models.Configuration propertyConfiguration) => _PropertyConfiguration = propertyConfiguration; + + public void Update() => _PropertyConfiguration?.Update(); + +} \ No newline at end of file diff --git a/Date-Group/Models/Stateless/AppSettings.cs b/Date-Group/Models/Stateless/AppSettings.cs new file mode 100644 index 0000000..7c590af --- /dev/null +++ b/Date-Group/Models/Stateless/AppSettings.cs @@ -0,0 +1,40 @@ +using Microsoft.Extensions.Configuration; +using System.Text.Json; + +namespace View_by_Distance.Date.Group.Models.Stateless; + +public abstract class AppSettings +{ + + public static Models.AppSettings Get(IConfigurationRoot configurationRoot) + { + Models.AppSettings? result; + Binder.AppSettings appSettings = configurationRoot.Get(); + string json = JsonSerializer.Serialize(appSettings, new JsonSerializerOptions() { WriteIndented = true }); + result = JsonSerializer.Deserialize(json); + if (result is null) + throw new Exception(json); + if (string.IsNullOrEmpty(result.Company)) + throw new Exception(json); + string jsonThis = result.ToString(); + if (jsonThis != json) + { + int? check = null; + int min = new int[] { json.Length, jsonThis.Length }.Min(); + for (int i = 0; i < min; i++) + { + if (json[i] == jsonThis[i]) + continue; + check = i; + break; + } + if (check is null) + throw new Exception(); + string a = json[..check.Value].Split(',')[^1]; + string b = json[check.Value..].Split(',')[0]; + throw new Exception($"{a}{b}"); + } + return result; + } + +} \ No newline at end of file diff --git a/Date-Group/Models/Stateless/Configuration.cs b/Date-Group/Models/Stateless/Configuration.cs new file mode 100644 index 0000000..eeaea37 --- /dev/null +++ b/Date-Group/Models/Stateless/Configuration.cs @@ -0,0 +1,44 @@ +using Microsoft.Extensions.Configuration; +using Phares.Shared; +using System.Text.Json; + +namespace View_by_Distance.Date.Group.Models.Stateless; + +public abstract class Configuration +{ + + public static Models.Configuration Get(IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, string workingDirectory, Property.Models.Configuration propertyConfiguration) + { + Models.Configuration? result; + string environmentName = IsEnvironment.GetEnvironmentName(isEnvironment); + string section = string.Concat(environmentName, ":", nameof(Binder.Configuration)); + IConfigurationSection configurationSection = configurationRoot.GetSection(section); + Binder.Configuration configuration = configurationSection.Get(); + string json = JsonSerializer.Serialize(configuration, new JsonSerializerOptions() { WriteIndented = true }); + result = JsonSerializer.Deserialize(json); + if (result is null) + throw new Exception(json); + string jsonThis = result.ToString(); + result.Set(propertyConfiguration); + result.Update(); + if (jsonThis != json) + { + int? check = null; + int min = new int[] { json.Length, jsonThis.Length }.Min(); + for (int i = 0; i < min; i++) + { + if (json[i] == jsonThis[i]) + continue; + check = i; + break; + } + if (check is null) + throw new Exception(); + string a = json[..check.Value].Split(',')[^1]; + string b = json[check.Value..].Split(',')[0]; + throw new Exception($"{a}{b}"); + } + return result; + } + +} \ No newline at end of file diff --git a/Date-Group/Models/Stateless/SerilogExtensionMethods.cs b/Date-Group/Models/Stateless/SerilogExtensionMethods.cs new file mode 100644 index 0000000..f36a943 --- /dev/null +++ b/Date-Group/Models/Stateless/SerilogExtensionMethods.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Date.Group.Models.Stateless; + +public static class SerilogExtensionMethods +{ + + internal static void Warn(this Serilog.ILogger log, string messageTemplate) => log.Warning(messageTemplate); + + internal static void Info(this Serilog.ILogger log, string messageTemplate) => log.Information(messageTemplate); + +} \ No newline at end of file diff --git a/Date-Group/Program.cs b/Date-Group/Program.cs new file mode 100644 index 0000000..8a36aba --- /dev/null +++ b/Date-Group/Program.cs @@ -0,0 +1,109 @@ +using Microsoft.Extensions.Configuration; +using Phares.Shared; +using Serilog; +using System.Diagnostics; +using System.Reflection; +using View_by_Distance.Date.Group.Models; +using View_by_Distance.Shared.Models.Stateless.Methods; + +namespace View_by_Distance.Date.Group; + +public class Program +{ + + public static void Secondary(List args) + { + LoggerConfiguration loggerConfiguration = new(); + Assembly assembly = Assembly.GetExecutingAssembly(); + bool debuggerWasAttachedAtLineZero = Debugger.IsAttached || assembly.Location.Contains(@"\bin\Debug"); + IsEnvironment isEnvironment = new(processesCount: null, nullASPNetCoreEnvironmentIsDevelopment: debuggerWasAttachedAtLineZero, nullASPNetCoreEnvironmentIsProduction: !debuggerWasAttachedAtLineZero); + IConfigurationBuilder configurationBuilder = new ConfigurationBuilder() + .AddEnvironmentVariables() + .AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true); + IConfigurationRoot configurationRoot = configurationBuilder.Build(); + AppSettings appSettings = Models.Stateless.AppSettings.Get(configurationRoot); + if (appSettings.MaxDegreeOfParallelism is null) + throw new Exception("MaxDegreeOfParallelism must be set!"); + if (appSettings.MaxDegreeOfParallelism.Value > Environment.ProcessorCount) + throw new Exception("MaxDegreeOfParallelism must be =< Environment.ProcessorCount!"); + if (string.IsNullOrEmpty(appSettings.WorkingDirectoryName)) + throw new Exception("Working directory name must have a value!"); + string workingDirectory = IWorkingDirectory.GetWorkingDirectory(assembly.GetName().Name, appSettings.WorkingDirectoryName); + Environment.SetEnvironmentVariable(nameof(workingDirectory), workingDirectory); + _ = ConfigurationLoggerConfigurationExtensions.Configuration(loggerConfiguration.ReadFrom, configurationRoot); + Log.Logger = loggerConfiguration.CreateLogger(); + ILogger log = Log.ForContext(); + int silentIndex = args.IndexOf("s"); + if (silentIndex > -1) + args.RemoveAt(silentIndex); + try + { + if (args is null) + throw new Exception("args is null!"); +#nullable disable + if (Property.Models.Stateless.A_Property.IsWrongYear("-".Split(' '), "2021").Item1.HasValue) + throw new Exception("-"); + if (Property.Models.Stateless.A_Property.IsWrongYear("Christmass".Split(' '), "2021").Item1.HasValue) + throw new Exception("Christmass"); + if (Property.Models.Stateless.A_Property.IsWrongYear("Christmass 2021".Split(' '), "2021").Item1.Value) + throw new Exception("Christmass"); + if (Property.Models.Stateless.A_Property.IsWrongYear("Christmass ~2021".Split(' '), "2021").Item1.Value) + throw new Exception("Christmass"); + if (Property.Models.Stateless.A_Property.IsWrongYear("Christmass ~2021.4".Split(' '), "2021").Item1.Value) + throw new Exception("Christmass"); + if (!Property.Models.Stateless.A_Property.IsWrongYear("Christmass 2021".Split(' '), "2025").Item1.Value) + throw new Exception("Christmass"); + if (!Property.Models.Stateless.A_Property.IsWrongYear("Christmass ~2021".Split(' '), "2025").Item1.Value) + throw new Exception("Christmass"); + if (!Property.Models.Stateless.A_Property.IsWrongYear("Christmass ~2021.4".Split(' '), "2025").Item1.Value) + throw new Exception("Christmass"); + if (Property.Models.Stateless.A_Property.IsWrongYear("England 2017".Split(' '), "2017").Item1.Value) + throw new Exception("England"); + if (Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael".Split(' '), "2021").Item1.HasValue) + throw new Exception("Logan Michael"); + if (Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael 2021".Split(' '), "2021").Item1.Value) + throw new Exception("Logan Michael"); + if (Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael ~2021".Split(' '), "2021").Item1.Value) + throw new Exception("Logan Michael"); + if (Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael ~2021.4".Split(' '), "2021").Item1.Value) + throw new Exception("Logan Michael"); + if (!Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael 2021".Split(' '), "2025").Item1.Value) + throw new Exception("Logan Michael"); + if (!Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael ~2021".Split(' '), "2025").Item1.Value) + throw new Exception("Logan Michael"); + if (!Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael ~2021.4".Split(' '), "2025").Item1.Value) + throw new Exception("Logan Michael"); + if (Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael ~2021.4".Split(' '), "2021").Item2[0] != "~2021.4") + throw new Exception("Logan Michael"); + if (Property.Models.Stateless.A_Property.IsWrongYear("Chelsea's 2nd Birthday =2014".Split(' '), "2014").Item1.Value) + throw new Exception("Chelsea"); +#nullable restore + Shared.Models.Console console = new(); + DateGroup _ = new(args, isEnvironment, configurationRoot, appSettings, workingDirectory, silentIndex > -1, console); + } + catch (Exception ex) + { + log.Fatal(string.Concat(ex.Message, Environment.NewLine, ex.StackTrace)); + } + finally + { + Log.CloseAndFlush(); + } + if (silentIndex > -1) + log.Debug("Done. Bye"); + else + { + log.Debug("Done. Press 'Enter' to end"); + _ = Console.ReadLine(); + } + } + + public static void Main(string[] args) + { + if (args is not null) + Secondary(args.ToList()); + else + Secondary(new List()); + } + +} \ No newline at end of file diff --git a/Date-Group/appsettings.Development.json b/Date-Group/appsettings.Development.json new file mode 100644 index 0000000..9069b83 --- /dev/null +++ b/Date-Group/appsettings.Development.json @@ -0,0 +1,342 @@ +{ + "Company": "Mike Phares", + "Linux": {}, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Log4netProvider": "Debug", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "MaxDegreeOfParallelism": 1, + "Serilog": { + "Using": [ + "Serilog.Sinks.Console", + "Serilog.Sinks.File" + ], + "MinimumLevel": "Debug", + "WriteTo": [ + { + "Name": "Debug", + "Args": { + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}" + } + }, + { + "Name": "Console", + "Args": { + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "%workingDirectory% - Log/log-.txt", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}", + "rollingInterval": "Hour" + } + } + ], + "Enrich": [ + "FromLogContext", + "WithMachineName", + "WithThreadId" + ], + "Properties": { + "Application": "Sample" + } + }, + "WorkingDirectoryName": "PharesApps", + "Windows": { + "Configuration": { + "ByDay": false, + "ByHash": false, + "BySeason": true, + "ByWeek": false, + "DateGroup": "2022-04-07", + "FileNameDirectorySeparator": ".Z.", + "ForcePropertyLastWriteTimeToCreationTime": false, + "KeepFullPath": false, + "MaxImagesInDirectoryForTopLevelFirstPass": 50, + "Pattern": "[^ABCDEFGHIJKLMNOPQRSTUVWXYZbcdfghjklmnpqrstvwxyz0-9]", + "PopulatePropertyId": false, + "PropertiesChangedForProperty": false, + "RootDirectory": "C:/Tmp/Phares/- Device Videos 2_0_0_3 - Current/_", + "WriteBitmapDataBytes": false, + "IgnoreExtensions": [ + ".gif", + ".GIF" + ], + "PropertyContentCollectionFiles": [], + "ValidImageFormatExtensions": [ + ".bmp", + ".BMP", + ".gif", + ".GIF", + ".jpeg", + ".JPEG", + ".jpg", + ".JPG", + ".png", + ".PNG", + ".tiff", + ".TIFF" + ], + "ValidMetadataExtensions": [ + ".3gp", + ".3GP", + ".amr", + ".AMR", + ".avi", + ".AVI", + ".bmp", + ".BMP", + ".gif", + ".GIF", + ".ico", + ".ICO", + ".jpeg", + ".JPEG", + ".jpg", + ".JPG", + ".m4v", + ".M4V", + ".mov", + ".MOV", + ".mp4", + ".MP4", + ".mta", + ".MTA", + ".png", + ".PNG", + ".tiff", + ".TIFF" + ], + "VerifyToSeason": [ + ". 2000", + ". 2001", + ". 2002", + ". 2003", + ". 2004", + ". 2005", + ". 2006", + ". 2007", + ". 2008", + ". 2009", + ". 2010", + ". 2011", + ". 2012", + ". 2013", + ". 2014", + ". 2015", + ". 2016", + ". 2017", + ". 2018", + ". 2019", + ". 2020", + ". 2021", + ". 2022", + ". 2023", + ". 2024", + ". 2025", + ". 2026", + ". 2027", + ". 2028", + ". 2029", + "=2000.0 Winter", + "=2002.1 Spring", + "=2002.4 Winter", + "=2003.0 Winter", + "=2003.1 Spring", + "=2003.3 Fall", + "=2003.4 Winter", + "=2004.0 Winter", + "=2005.1 Spring", + "=2005.2 Summer", + "=2005.3 Fall", + "=2005.4 Winter", + "=2006.0 Winter", + "=2006.1 Spring", + "=2006.3 Fall", + "=2007.0 Winter", + "=2007.2 Summer Logan Michael", + "=2007.2 Summer", + "=2007.3 Fall Logan Michael", + "=2007.4 Winter Logan Michael", + "=2008.0 Winter Logan Michael", + "=2008.1 Spring Logan Michael", + "=2008.2 Summer Logan Michael", + "=2008.2 Summer", + "=2008.3 Fall Logan Michael", + "=2009.0 Winter Logan Michael", + "=2009.0 Winter", + "=2009.1 Spring Logan Michael", + "=2009.1 Spring", + "=2009.2 Summer Logan Michael", + "=2009.2 Summer", + "=2009.3 Fall Logan Michael", + "=2009.3 Fall", + "=2009.4 Winter Logan Michael", + "=2009.4 Winter", + "=2010.0 Winter Logan Michael", + "=2010.0 Winter", + "=2010.1 Spring Logan Michael", + "=2010.1 Spring", + "=2010.2 Summer", + "=2010.3 Fall Logan Michael", + "=2010.3 Fall", + "=2010.4 Winter", + "=2011.0 Winter", + "=2011.1 Spring", + "=2011.2 Summer", + "=2011.3 Fall", + "=2011.4 Winter", + "=2012.0 Winter Chelsea 2012", + "=2012.0 Winter Chelsea", + "=2012.0 Winter", + "=2012.1 Spring Chelsea", + "=2012.1 Spring", + "=2012.2 Summer Chelsea", + "=2012.2 Summer", + "=2012.3 Fall Chelsea", + "=2012.3 Fall", + "=2012.4 Winter Chelsea", + "=2012.4 Winter", + "=2013.0 Winter Chelsea 2013", + "=2013.0 Winter Chelsea", + "=2013.0 Winter", + "=2013.1 Spring", + "=2013.2 Summer Chelsea", + "=2013.2 Summer", + "=2013.3 Fall Chelsea", + "=2013.3 Fall", + "=2013.4 Winter", + "=2014.0 Winter", + "=2014.1 Spring", + "=2014.2 Summer", + "=2014.3 Fall", + "=2014.4 Winter", + "=2015.0 Winter", + "=2015.1 Spring", + "=2015.2 Summer", + "=2015.3 Fall", + "=2015.4 Winter", + "=2016.0 Winter", + "=2016.1 Spring", + "=2016.2 Summer", + "=2016.3 Fall", + "=2016.4 Winter", + "=2017.1 Spring", + "=2017.2 Summer", + "=2017.3 Fall", + "=2017.4 Winter", + "=2018.0 Winter", + "=2018.1 Spring", + "=2018.3 Fall", + "=2018.4 Winter", + "=2019.0 Winter", + "=2019.1 Spring", + "=2019.2 Summer", + "=2019.3 Fall", + "=2019.4 Winter", + "=2020.0 Winter", + "=2020.1 Spring", + "=2020.2 Summer", + "=2020.3 Fall", + "=2020.4 Winter", + "=2021.1 Spring", + "=2021.2 Summer", + "=2021.3 Fall", + "=2021.4 Winter", + "=2022.0 Winter", + "=2022.1 Spring", + "Anthem 2015", + "April 2010", + "April 2013", + "December 2006", + "December 2010", + "Fall 2005", + "Fall 2015", + "Fall 2016", + "Fall 2017", + "Fall 2018", + "Fall 2019", + "Fall 2020", + "Fall 2021", + "February 2010", + "January 2015", + "July 2010", + "June 2010", + "Kids 2005", + "March 2013", + "May 2010", + "May 2011", + "May 2013", + "October 2005", + "October 2014", + "Spring 2013", + "Spring 2014", + "Spring 2016", + "Spring 2018", + "Spring 2019", + "Spring 2020", + "Summer 2011", + "Summer 2012", + "Summer 2013", + "Summer 2014", + "Summer 2015", + "Summer 2016", + "Summer 2017", + "Summer 2018", + "Summer 2020", + "Summer 2021", + "Winter 2015", + "Winter 2016", + "Winter 2017", + "Winter 2018", + "Winter 2019-2020", + "Winter 2020", + "zzz =2005.0 Winter Tracy Pictures", + "zzz =2005.1 Spring Tracy Pictures", + "zzz =2005.2 Summer Tracy Pictures", + "zzz =2005.3 Fall Tracy Pictures", + "zzz =2005.4 Winter Tracy Pictures", + "zzz =2006.1 Spring Tracy Pictures", + "zzz =2007.0 Winter Tracy Pictures", + "zzz =2007.2 Summer Tracy Pictures", + "zzz =2008.0 Winter Tracy Pictures", + "zzz =2008.2 Summer Tracy Pictures", + "zzz =2009.0 Winter Tracy Pictures", + "zzz =2009.2 Summer Tracy Pictures", + "zzz =2009.3 Fall Tracy Pictures", + "zzz =2009.4 Winter Tracy Pictures", + "zzz =2010.0 Winter Tracy Pictures", + "zzz =2010.1 Spring Tracy Pictures", + "zzz =2010.2 Summer Tracy Pictures", + "zzz =2010.3 Fall Tracy Pictures", + "zzz =2011.0 Winter Tracy Pictures", + "zzz =2011.1 Spring Tracy Pictures", + "zzz =2011.2 Summer Tracy Pictures", + "zzz =2011.3 Fall Tracy Pictures", + "zzz =2011.4 Winter Tracy Pictures", + "zzz =2012.0 Winter Tracy Pictures", + "zzz =2012.1 Spring Tracy Pictures", + "zzz =2012.2 Summer Tracy Pictures", + "zzz =2012.3 Fall Tracy Pictures", + "zzz =2012.4 Winter Tracy Pictures", + "zzz =2013.0 Winter Tracy Pictures", + "zzz =2013.1 Spring Tracy Pictures", + "zzz =2013.2 Summer Tracy Pictures", + "zzz =2013.3 Fall Tracy Pictures", + "zzz =2013.4 Winter Tracy Pictures", + "zzz =2014.0 Winter Tracy Pictures", + "zzz =2014.1 Spring Tracy Pictures", + "zzz =2014.2 Summer Tracy Pictures", + "zzz =2014.3 Fall Tracy Pictures", + "zzz =2014.4 Winter Tracy Pictures", + "zzz =2015.0 Winter Tracy Pictures" + ] + } + } +} \ No newline at end of file diff --git a/Instance/.vscode/format-report.json b/Instance/.vscode/format-report.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/Instance/.vscode/format-report.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/Instance/.vscode/launch.json b/Instance/.vscode/launch.json new file mode 100644 index 0000000..548fdc2 --- /dev/null +++ b/Instance/.vscode/launch.json @@ -0,0 +1,32 @@ +{ + "version": "0.2.0", + "configurations": [ + { + // Use IntelliSense to find out which attributes exist for C# debugging + // Use hover for the description of the existing attributes + // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md + "name": ".NET Core Launch (console)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + // If you have changed target frameworks, make sure to update the program path. + "program": "${workspaceFolder}/bin/x64/Debug/net6.0/win-x64/Instance.dll", + "args": [ + "s" + ], + "env": { + "ASPNETCORE_ENVIRONMENT": "Development", + }, + "cwd": "${workspaceFolder}", + // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console + "console": "externalTerminal", + "stopAtEntry": false + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach", + "processName": "Instance" + } + ] +} \ No newline at end of file diff --git a/Instance/.vscode/settings.json b/Instance/.vscode/settings.json new file mode 100644 index 0000000..7f910f7 --- /dev/null +++ b/Instance/.vscode/settings.json @@ -0,0 +1,14 @@ +{ + "cSpell.words": [ + "Bday", + "Blazor", + "Dlib", + "Exif", + "mmod", + "nameof", + "nosj", + "Phares", + "Serilog", + "Vericruz" + ] +} \ No newline at end of file diff --git a/Instance/.vscode/tasks.json b/Instance/.vscode/tasks.json new file mode 100644 index 0000000..dc6e867 --- /dev/null +++ b/Instance/.vscode/tasks.json @@ -0,0 +1,42 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/Instance.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "publish", + "command": "dotnet", + "type": "process", + "args": [ + "publish", + "${workspaceFolder}/Instance.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "watch", + "command": "dotnet", + "type": "process", + "args": [ + "watch", + "run", + "${workspaceFolder}/Instance.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/Instance/DlibDotNet.cs b/Instance/DlibDotNet.cs new file mode 100644 index 0000000..8078f71 --- /dev/null +++ b/Instance/DlibDotNet.cs @@ -0,0 +1,796 @@ +using FaceRecognitionDotNet; +using Microsoft.Extensions.Configuration; +using Phares.Shared; +using ShellProgressBar; +using System.Drawing.Imaging; +using System.Text.Json; +using View_by_Distance.Instance.Models; +using View_by_Distance.Metadata.Models; +using View_by_Distance.Property.Models; +using View_by_Distance.Resize.Models; +using View_by_Distance.Shared.Models.Methods; + +namespace View_by_Distance.Instance; + +public class DlibDotNet +{ + + private readonly D_Face _Faces; + private readonly G_Index _Index; + private readonly C_Resize _Resize; + private readonly F_Random _Random; + private readonly A2_People _People; + private readonly E3_Rename _Rename; + private readonly B_Metadata _Metadata; + private readonly E_Distance _Distance; + private readonly Serilog.ILogger? _Log; + private readonly AppSettings _AppSettings; + private readonly List _Exceptions; + private readonly IsEnvironment _IsEnvironment; + private readonly D2_FaceLandmarks _FaceLandmarks; + private readonly Models.Configuration _Configuration; + private readonly bool _ArgZeroIsConfigurationRootDirectory; + private readonly List> _FileKeyValuePairs; + private readonly Dictionary>> _FilePropertiesKeyValuePairs; + + public DlibDotNet(List args, IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, AppSettings appSettings, string workingDirectory, bool isSilent, IConsole console) + { + string argZero; + _AppSettings = appSettings; + if (appSettings.MaxDegreeOfParallelism is null) + throw new Exception($"{nameof(appSettings.MaxDegreeOfParallelism)} is null!"); + _IsEnvironment = isEnvironment; + _Exceptions = new List(); + _Log = Serilog.Log.ForContext(); + _FileKeyValuePairs = new List>(); + _FilePropertiesKeyValuePairs = new Dictionary>>(); + Property.Models.Configuration propertyConfiguration = Property.Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory); + Property.Models.Configuration.Verify(propertyConfiguration); + Models.Configuration configuration = Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory, propertyConfiguration); + Verify(configuration); + (Model model, PredictorModel predictorModel) = GetTuple(args, propertyConfiguration, configuration); + if (configuration.SearchForAbandonedFilesFull is null) + throw new Exception($"{nameof(configuration.SearchForAbandonedFilesFull)} is null!"); + _Configuration = configuration; + _Index = new G_Index(configuration); + _Random = new F_Random(configuration); + _People = new A2_People(configuration); + _Rename = new E3_Rename(configuration); + _Distance = new E_Distance(configuration); + _FaceLandmarks = new D2_FaceLandmarks(configuration); + if (configuration.ForceMetadataLastWriteTimeToCreationTime is null) + throw new Exception($"{nameof(configuration.ForceMetadataLastWriteTimeToCreationTime)} is null!"); + if (configuration.ForceResizeLastWriteTimeToCreationTime is null) + throw new Exception($"{nameof(configuration.ForceResizeLastWriteTimeToCreationTime)} is null!"); + if (configuration.IgnoreExtensions is null) + throw new Exception($"{nameof(configuration.IgnoreExtensions)} is null!"); + if (configuration.OutputQuality is null) + throw new Exception($"{nameof(configuration.OutputQuality)} is null!"); + if (configuration.OverrideForResizeImages is null) + throw new Exception($"{nameof(configuration.OverrideForResizeImages)} is null!"); + if (configuration.PropertiesChangedForMetadata is null) + throw new Exception($"{nameof(configuration.PropertiesChangedForMetadata)} is null!"); + if (configuration.PropertiesChangedForResize is null) + throw new Exception($"{nameof(configuration.PropertiesChangedForResize)} is null!"); + _Metadata = new(configuration.ForceMetadataLastWriteTimeToCreationTime.Value, configuration.PropertiesChangedForMetadata.Value); + if (args.Count > 0) + argZero = Path.GetFullPath(args[0]); + else + argZero = Path.GetFullPath(propertyConfiguration.RootDirectory); + _ArgZeroIsConfigurationRootDirectory = propertyConfiguration.RootDirectory == argZero; + (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters) = C_Resize.GetTuple(configuration.OutputExtension, configuration.OutputQuality.Value); + _Resize = new C_Resize(configuration.ForceResizeLastWriteTimeToCreationTime.Value, configuration.OverrideForResizeImages.Value, configuration.PropertiesChangedForResize.Value, configuration.ValidResolutions, imageCodecInfo, encoderParameters); + ModelParameter modelParameter = new() + { + CnnFaceDetectorModel = File.ReadAllBytes(Path.Combine(configuration.ModelDirectory, "mmod_human_face_detector.dat")), + FaceRecognitionModel = File.ReadAllBytes(Path.Combine(configuration.ModelDirectory, "dlib_face_recognition_resnet_model_v1.dat")), + PosePredictor5FaceLandmarksModel = File.ReadAllBytes(Path.Combine(configuration.ModelDirectory, "shape_predictor_5_face_landmarks.dat")), + PosePredictor68FaceLandmarksModel = File.ReadAllBytes(Path.Combine(configuration.ModelDirectory, "shape_predictor_68_face_landmarks.dat")) + }; + _Faces = new D_Face(configuration, argZero, model, modelParameter, predictorModel); + if (configuration.SkipSearch is null) + throw new Exception($"{nameof(configuration.SkipSearch)} is null!"); + if (_ArgZeroIsConfigurationRootDirectory) + _ = _People.GetPeople(propertyConfiguration); + if (!isSilent && configuration.TestDistanceResults.HasValue && configuration.TestDistanceResults.Value) + { + E2_Navigate e2Navigate = new(console, configuration, argZero); + e2Navigate.Navigate(propertyConfiguration, configuration.OutputResolutions[0]); + } + if (_ArgZeroIsConfigurationRootDirectory) + { + long ticks = DateTime.Now.Ticks; + string[] directories = Property.Models.Stateless.A_Property.GetDirectoryRenameCollection(propertyConfiguration, configuration.OutputResolutions[0], nameof(B_Metadata), nameof(C_Resize)); + foreach (string directory in directories) + { + if (!Directory.Exists(directory)) + continue; + Property.Models.Stateless.A_Property.SearchForAbandonedFilesFull(argZero, directory, onlyJson: false); + } + if (appSettings.MaxDegreeOfParallelism.Value < 2) + ticks = LogDelta(ticks, nameof(Property.Models.Stateless.A_Property.SearchForAbandonedFilesFull)); + } + if (!configuration.SkipSearch.Value) + Search(argZero); + if (_Exceptions.Count == 0 && _ArgZeroIsConfigurationRootDirectory) + { + long ticks = DateTime.Now.Ticks; + if (configuration.SearchForAbandonedFilesFull.Value) + { + string[] directories = _Rename.GetDirectoryRenameCollection(propertyConfiguration, relativePath: string.Empty, newDirectoryName: string.Empty, jsonFiles4InfoAny: false); + foreach (string directory in directories) + { + if (!Directory.Exists(directory)) + continue; + Property.Models.Stateless.A_Property.SearchForAbandonedFilesFull(argZero, directory, onlyJson: true); + } + if (appSettings.MaxDegreeOfParallelism.Value < 2) + ticks = LogDelta(ticks, nameof(Property.Models.Stateless.A_Property.SearchForAbandonedFilesFull)); + } + List directoryCollections = _Rename.GetDirectoryRenameCollections(propertyConfiguration, relativePath: string.Empty, newDirectoryName: string.Empty, jsonFiles4InfoAny: false); + foreach (string[] directoryCollection in directoryCollections) + { + _Log.Information(string.Concat("Cleaning <", directoryCollection[0], ">")); + _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(directoryCollection[0]); + } + string d2FaceLandmarksRootDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(propertyConfiguration, nameof(D2_FaceLandmarks)); + _Log.Information(string.Concat("Cleaning <", d2FaceLandmarksRootDirectory, ">")); + _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(d2FaceLandmarksRootDirectory); + if (appSettings.MaxDegreeOfParallelism.Value < 2) + ticks = LogDelta(ticks, nameof(Property.Models.Stateless.IPath.DeleteEmptyDirectories)); + } + string message = $"There were {_Exceptions.Count} exception(s) thrown! {Environment.NewLine}{string.Join(Environment.NewLine, _Exceptions)}"; + _Log.Information(message); + if (_Exceptions.Count != 0) + throw new Exception(message); + if (configuration.LoadOrCreateThenSaveDirectoryDistanceResults is null) + throw new Exception($"{nameof(configuration.LoadOrCreateThenSaveDirectoryDistanceResults)} is null!"); + if (configuration.LoadOrCreateThenSaveDirectoryDistanceResults.Value) + { + long ticks = DateTime.Now.Ticks; + foreach (string outputResolution in configuration.OutputResolutions) + _Distance.LoadOrCreateThenSaveDirectoryDistanceResults(propertyConfiguration, outputResolution); + if (appSettings.MaxDegreeOfParallelism.Value < 2) + ticks = LogDelta(ticks, nameof(E_Distance.LoadOrCreateThenSaveDirectoryDistanceResults)); + } + } + + private long LogDelta(long ticks, string methodName) + { + long result; + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + double delta = new TimeSpan(DateTime.Now.Ticks - ticks).TotalMilliseconds; + _Log.Debug($"{methodName} took {Math.Floor(delta)} millisecond(s)"); + result = DateTime.Now.Ticks; + return result; + } + +#pragma warning disable CA1416 +#pragma warning restore CA1416 + + private (Model Model, PredictorModel PredictorModel) GetTuple(List args, Property.Models.Configuration propertyConfiguration, Models.Configuration configuration) + { + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + (Model Model, PredictorModel PredictorModel) result; + Array array; + Model? model = null; + string[] sourceDirectoryNames; + PredictorModel? predictorModel = null; + if (!args.Any()) + sourceDirectoryNames = Array.Empty(); + else + { + string argZero = Path.GetFullPath(args[0]); + sourceDirectoryNames = argZero.Split(Path.DirectorySeparatorChar); + if (!argZero.StartsWith(propertyConfiguration.RootDirectory)) + throw new Exception($"Source directory must be inside root directory! <{argZero}> <{propertyConfiguration.RootDirectory}>"); + if (_ArgZeroIsConfigurationRootDirectory && propertyConfiguration.RootDirectory != argZero) + { + if (!configuration.MixedYearRelativePaths.Contains(sourceDirectoryNames[0])) + { + string[] segments = sourceDirectoryNames[0].Split(' '); + if (segments.Length < 2 || segments[^1].Length != 4 || (segments[^1][..2] != "19" && segments[^1][..2] != "20")) + throw new Exception("root subdirectory must have a year at the end or directory name needs to be added to the exclude list!"); + } + } + } + _Log.Information(configuration.ModelDirectory); + string[] resizeMatch = (from l in sourceDirectoryNames where configuration.ValidResolutions.Contains(l) select l).ToArray(); + if (resizeMatch.Any()) + throw new Exception("Input directory should be the source and not a resized directory!"); + array = Enum.GetValues(typeof(Model)); + foreach (Model check in array) + { + if (configuration.ModelName.Contains(check.ToString())) + { + model = check; + break; + } + } + if (model is null) + throw new Exception("Destination directory must have Model name!"); + model = model.Value; + array = Enum.GetValues(typeof(PredictorModel)); + foreach (PredictorModel check in array) + { + if (configuration.PredictorModelName.Contains(check.ToString())) + { + predictorModel = check; + break; + } + } + if (predictorModel is null) + throw new Exception("Destination directory must have Predictor Model name!"); + predictorModel = predictorModel.Value; + result = new(model.Value, predictorModel.Value); + return result; + } + + private void Verify(Models.Configuration configuration) + { + if (!configuration.OutputResolutions.Any() || string.IsNullOrEmpty(configuration.OutputResolutions[0]) || !configuration.ValidResolutions.Contains(configuration.OutputResolutions[0])) + throw new Exception($"{nameof(configuration.OutputResolutions)} must be a valid outputResolution!"); + if ((from l in configuration.OutputResolutions where !configuration.ValidResolutions.Contains(l) select false).Any()) + throw new Exception($"One or more {nameof(configuration.OutputResolutions)} are not in the ValidResolutions list!"); + if ((from l in configuration.SaveFaceLandmarkForOutputResolutions where !configuration.ValidResolutions.Contains(l) select false).Any()) + throw new Exception($"One or more {nameof(configuration.SaveFaceLandmarkForOutputResolutions)} are not in the ValidResolutions list!"); + if (configuration.CheckJsonForDistanceResults is null) + throw new Exception($"{nameof(configuration.CheckJsonForDistanceResults)} must be set!"); + if (configuration.CrossDirectoryMaxItemsInDistanceCollection is null) + throw new Exception($"{nameof(configuration.CrossDirectoryMaxItemsInDistanceCollection)} must be set!"); + if (configuration.DistanceFactor is null) + throw new Exception($"{nameof(configuration.DistanceFactor)} must be set!"); + if (configuration.ForceMetadataLastWriteTimeToCreationTime is null) + throw new Exception($"{nameof(configuration.ForceMetadataLastWriteTimeToCreationTime)} must be set!"); + if (configuration.ForceResizeLastWriteTimeToCreationTime is null) + throw new Exception($"{nameof(configuration.ForceResizeLastWriteTimeToCreationTime)} must be set!"); + if (configuration.IgnoreExtensions is null) + throw new Exception($"{nameof(configuration.IgnoreExtensions)} must be set!"); + if (configuration.IgnoreRelativePaths is null) + throw new Exception($"{nameof(configuration.IgnoreRelativePaths)} must be set!"); + if (configuration.LoadOrCreateThenSaveDirectoryDistanceResults is null) + throw new Exception($"{nameof(configuration.LoadOrCreateThenSaveDirectoryDistanceResults)} must be set!"); + if (configuration.LoadOrCreateThenSaveDistanceResults is null) + throw new Exception($"{nameof(configuration.LoadOrCreateThenSaveDistanceResults)} must be set!"); + if (configuration.LoadOrCreateThenSaveImageFacesResults is null) + throw new Exception($"{nameof(configuration.LoadOrCreateThenSaveImageFacesResults)} must be set!"); + if (configuration.LoadOrCreateThenSaveIndex is null) + throw new Exception($"{nameof(configuration.LoadOrCreateThenSaveIndex)} must be set!"); + if (configuration.LocationConfidenceFactor is null) + throw new Exception($"{nameof(configuration.LocationConfidenceFactor)} must be set!"); + if (configuration.MappedMaxIndex is null) + throw new Exception($"{nameof(configuration.MappedMaxIndex)} must be set!"); + if (configuration.MappedMaxIndex.HasValue && configuration.LoadOrCreateThenSaveIndex.Value && !_IsEnvironment.DebuggerWasAttachedDuringConstructor) + throw new Exception($"{nameof(configuration.MappedMaxIndex)} only allowed when debugger is attached!"); + if (configuration.MaxItemsInDistanceCollection is null) + throw new Exception($"{nameof(configuration.MaxItemsInDistanceCollection)} must be set!"); + if (configuration.MixedYearRelativePaths is null) + throw new Exception($"{nameof(configuration.MixedYearRelativePaths)} must be set!"); + if (configuration.NumJitters is null) + throw new Exception($"{nameof(configuration.NumJitters)} must be set!"); + if (configuration.OutputQuality is null) + throw new Exception($"{nameof(configuration.OutputQuality)} must be set!"); + if (configuration.OutputResolutions is null) + throw new Exception($"{nameof(configuration.OutputResolutions)} must be set!"); + if (configuration.OverrideForFaceImages is null) + throw new Exception($"{nameof(configuration.OverrideForFaceImages)} must be set!"); + if (configuration.OverrideForFaceLandmarkImages is null) + throw new Exception($"{nameof(configuration.OverrideForFaceLandmarkImages)} must be set!"); + if (configuration.OverrideForResizeImages is null) + throw new Exception($"{nameof(configuration.OverrideForResizeImages)} must be set!"); + if (configuration.PaddingLoops is null) + throw new Exception($"{nameof(configuration.PaddingLoops)} must be set!"); + if (configuration.PropertiesChangedForDistance is null) + throw new Exception($"{nameof(configuration.PropertiesChangedForDistance)} must be set!"); + if (configuration.PropertiesChangedForFaces is null) + throw new Exception($"{nameof(configuration.PropertiesChangedForFaces)} must be set!"); + if (configuration.PropertiesChangedForIndex is null) + throw new Exception($"{nameof(configuration.PropertiesChangedForIndex)} must be set!"); + if (configuration.PropertiesChangedForMetadata is null) + throw new Exception($"{nameof(configuration.PropertiesChangedForMetadata)} must be set!"); + if (configuration.PropertiesChangedForResize is null) + throw new Exception($"{nameof(configuration.PropertiesChangedForResize)} must be set!"); + if (configuration.Reverse is null) + throw new Exception($"{nameof(configuration.Reverse)} must be set!"); + if (configuration.SaveFaceLandmarkForOutputResolutions is null) + throw new Exception($"{nameof(configuration.SaveFaceLandmarkForOutputResolutions)} must be set!"); + if (configuration.SaveFullYearOfRandomFiles is null) + throw new Exception($"{nameof(configuration.SaveFullYearOfRandomFiles)} must be set!"); + if (configuration.SaveResizedSubfiles is null) + throw new Exception($"{nameof(configuration.SaveResizedSubfiles)} must be set!"); + if (configuration.SearchForAbandonedFilesFull is null) + throw new Exception($"{nameof(configuration.SearchForAbandonedFilesFull)} must be set!"); + if (configuration.SkipSearch is null) + throw new Exception($"{nameof(configuration.SkipSearch)} must be set!"); + if (configuration.TestDistanceResults is null) + throw new Exception($"{nameof(configuration.TestDistanceResults)} must be set!"); + if (configuration.ValidResolutions is null) + throw new Exception($"{nameof(configuration.ValidResolutions)} must be set!"); + if (string.IsNullOrEmpty(configuration.ModelDirectory) || !Directory.Exists(configuration.ModelDirectory)) + throw new Exception($"{nameof(configuration.ModelDirectory)} must have a value and exits!"); + if (string.IsNullOrEmpty(configuration.ModelName)) + throw new Exception($"{nameof(configuration.ModelName)} must have a value!"); + if (string.IsNullOrEmpty(configuration.OutputExtension)) + throw new Exception($"{nameof(configuration.OutputExtension)} must have a value!"); + if (string.IsNullOrEmpty(configuration.PredictorModelName)) + throw new Exception($"{nameof(configuration.PredictorModelName)} must have a value!"); + if (configuration.DistanceFactor.Value + configuration.LocationConfidenceFactor.Value != 10) + throw new Exception($"{nameof(configuration.DistanceFactor)} and {nameof(configuration.LocationConfidenceFactor)} must add up to 10!"); + } + + private int FullParallelWork(object @lock, long ticks, PropertyLogic propertyLogic, string outputResolution, List> sourceDirectoryChanges, List propertyFileInfoCollection, List propertyCollection, List>> metadataCollection, List> resizeKeyValuePairs, List> faceCollections, int g, string sourceDirectory, int r, string[] filteredSourceDirectoryFiles, int count) + { + int result = 0; + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + if (_AppSettings.MaxDegreeOfParallelism is null) + throw new Exception($"{nameof(AppSettings.MaxDegreeOfParallelism)} is null!"); + ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = _AppSettings.MaxDegreeOfParallelism.Value }; + ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; + if (faceCollections.Count != filteredSourceDirectoryFiles.Length || metadataCollection.Count != filteredSourceDirectoryFiles.Length || resizeKeyValuePairs.Count != filteredSourceDirectoryFiles.Length || propertyCollection.Count != filteredSourceDirectoryFiles.Length) + { + for (int i = 0; i < filteredSourceDirectoryFiles.Length; i++) + { + faceCollections.Add(new()); + metadataCollection.Add(new()); + resizeKeyValuePairs.Add(new()); + propertyCollection.Add(new()); + propertyFileInfoCollection.Add(null); + } + } + int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); + using (ProgressBar progressBar = new(filteredSourceDirectoryFiles.Length, $"{g}) {r + 1:000} / {count:000} - {outputResolution} - {sourceDirectory} - {filteredSourceDirectoryFiles.Length} file(s) - {totalSeconds} total second(s)", options)) + { + _ = Parallel.For(0, filteredSourceDirectoryFiles.Length, parallelOptions, i => + { + try + { + FullParallelForWork(propertyLogic, @lock, outputResolution, sourceDirectoryChanges, propertyFileInfoCollection, propertyCollection, metadataCollection, resizeKeyValuePairs, faceCollections, sourceDirectory, index: i, filteredSourceDirectoryFiles[i]); + if (sourceDirectoryChanges.Any()) + progressBar.Tick(); + } + catch (Exception ex) + { + result += 1; + _Log.Error(string.Concat(sourceDirectory, Environment.NewLine, ex.Message, Environment.NewLine, ex.StackTrace), ex); + if (result == filteredSourceDirectoryFiles.Length) + throw new Exception(string.Concat("All in [", sourceDirectory, "]failed!")); + } + }); + } + return result; + } + + private void FullParallelForWork(PropertyLogic propertyLogic, object @lock, string outputResolution, List> sourceDirectoryChanges, List propertyFileInfoCollection, List propertyCollection, List>> metadataCollections, List> resizeKeyValuePairs, List> imageFaceCollections, string sourceDirectory, int index, string filteredSourceDirectoryFile) + { + if (_AppSettings.MaxDegreeOfParallelism is null) + throw new Exception($"{nameof(_AppSettings.MaxDegreeOfParallelism)} is null!"); + if (_Configuration.SaveResizedSubfiles is null) + throw new Exception($"{nameof(_Configuration.SaveResizedSubfiles)} is null!"); + if (_Configuration?.PropertyConfiguration is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + if (_Configuration.PropertyConfiguration.WriteBitmapDataBytes is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration.WriteBitmapDataBytes)} is null!"); + List faceCollection; + string original = "Original"; + long ticks = DateTime.Now.Ticks; + DateTime dateTime = DateTime.Now; + List parseExceptions = new(); + Dictionary imageResizeKeyValuePairs; + List> subFileTuples = new(); + List> metadataCollection; + string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(filteredSourceDirectoryFile); + string relativePath = Property.Models.Stateless.IPath.GetRelativePath(filteredSourceDirectoryFile, _Configuration.PropertyConfiguration.RootDirectory.Length); + FileInfo propertyFileInfo = new(Path.Combine(propertyLogic.AngleBracketCollection[0].Replace("<>", "{}"), string.Concat(fileNameWithoutExtension, ".json"))); + A_Property property = propertyLogic.GetProperty(propertyLogic.AngleBracketCollection[0], sourceDirectory, filteredSourceDirectoryFile, subFileTuples, parseExceptions, propertyFileInfo); + if (_AppSettings.MaxDegreeOfParallelism.Value < 2) + ticks = LogDelta(ticks, nameof(PropertyLogic.GetProperty)); + (int metadataGroups, metadataCollection) = _Metadata.GetMetadataCollection(subFileTuples, parseExceptions, filteredSourceDirectoryFile, relativePath, fileNameWithoutExtension); + if (_AppSettings.MaxDegreeOfParallelism.Value < 2) + ticks = LogDelta(ticks, nameof(B_Metadata.GetMetadataCollection)); + FileInfo resizedFileInfo = new(Path.Combine(_Resize.AngleBracketCollection[0].Replace("<>", "()"), Path.GetFileName(filteredSourceDirectoryFile))); + imageResizeKeyValuePairs = _Resize.GetResizeKeyValuePairs(subFileTuples, parseExceptions, original, metadataCollection, property, filteredSourceDirectoryFile, relativePath, fileNameWithoutExtension); + if (_AppSettings.MaxDegreeOfParallelism.Value < 2) + ticks = LogDelta(ticks, nameof(C_Resize.GetResizeKeyValuePairs)); + if (_Configuration.SaveResizedSubfiles.Value) + { + _Resize.SaveResizedSubfile(outputResolution, subFileTuples, filteredSourceDirectoryFile, original, property, imageResizeKeyValuePairs, resizedFileInfo); + if (_AppSettings.MaxDegreeOfParallelism.Value < 2) + ticks = LogDelta(ticks, nameof(C_Resize.SaveResizedSubfile)); + resizedFileInfo.Refresh(); + } + else if (outputResolution == _Configuration.OutputResolutions[0] && false) + { + byte[] bytes = _Resize.GetResizedBytes(outputResolution, subFileTuples, filteredSourceDirectoryFile, property, imageResizeKeyValuePairs); + if (_AppSettings.MaxDegreeOfParallelism.Value < 2) + ticks = LogDelta(ticks, nameof(C_Resize.GetResizedBytes)); + string path = Path.Combine(resizedFileInfo.DirectoryName, Path.GetFileNameWithoutExtension(resizedFileInfo.Name)); + File.WriteAllBytes(path, bytes); + } + if (_Configuration.LoadOrCreateThenSaveImageFacesResults is null || !_Configuration.LoadOrCreateThenSaveImageFacesResults.Value) + faceCollection = new(); + else + { + int[] outputResolutionCollection = imageResizeKeyValuePairs[outputResolution]; + int outputResolutionWidth = outputResolutionCollection[0]; + int outputResolutionHeight = outputResolutionCollection[1]; + int outputResolutionOrientation = outputResolutionCollection[2]; + faceCollection = _Faces.GetFaces(_Configuration.PropertyConfiguration, outputResolution, subFileTuples, parseExceptions, relativePath, fileNameWithoutExtension, property, resizedFileInfo, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation); + if (_AppSettings.MaxDegreeOfParallelism.Value < 2) + ticks = LogDelta(ticks, nameof(D_Face.GetFaces)); + _Faces.SaveFaces(_Configuration.PropertyConfiguration, subFileTuples, parseExceptions, relativePath, fileNameWithoutExtension, resizedFileInfo, faceCollection); + if (_AppSettings.MaxDegreeOfParallelism.Value < 2) + ticks = LogDelta(ticks, nameof(D_Face.SaveFaces)); + if (_Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution)) + { + _FaceLandmarks.SaveFaceLandmarkImages(subFileTuples, parseExceptions, relativePath, fileNameWithoutExtension, resizedFileInfo, faceCollection); + if (_AppSettings.MaxDegreeOfParallelism.Value < 2) + ticks = LogDelta(ticks, nameof(D2_FaceLandmarks.SaveFaceLandmarkImages)); + } + } + lock (@lock) + { + propertyCollection[index] = property; + imageFaceCollections[index] = faceCollection; + metadataCollections[index] = metadataCollection; + propertyFileInfoCollection[index] = propertyFileInfo; + resizeKeyValuePairs[index] = imageResizeKeyValuePairs; + sourceDirectoryChanges.AddRange(from l in subFileTuples where l.Item2 > dateTime select l); + } + } + + private static void WriteTab(string checkDirectory, List<(string Id, string Line)> metadataIdLines, string fileName) + { + string text; + FileInfo fileInfo; + List duplicates = new(); + List metadataIds = new(); + fileInfo = new(Path.Combine(checkDirectory, "[()]", Path.ChangeExtension(fileName, "tsv"))); + if (fileInfo?.Directory is null) + throw new Exception(); + if (!fileInfo.Directory.Exists) + fileInfo.Directory.Create(); + foreach ((string Id, string Line) metadataIdLine in metadataIdLines) + { + if (metadataIds.Contains(metadataIdLine.Id)) + duplicates.Add(metadataIdLine.Id); + else + metadataIds.Add(metadataIdLine.Id); + } + for (int i = metadataIdLines.Count - 1; i > -1; i--) + { + if (duplicates.Contains(metadataIdLines[i].Id)) + metadataIdLines.RemoveAt(i); + } + if (metadataIdLines.Any()) + { + text = string.Join(Environment.NewLine, from l in metadataIdLines orderby l.Id select l.Line); + _ = Property.Models.Stateless.IPath.WriteAllText(fileInfo.FullName, text, compareBeforeWrite: true); + } + else + { + if (fileInfo.Exists) + File.Delete(fileInfo.FullName); + } + } + + private void WriteGroup(PropertyLogic propertyLogic, List propertyCollection, List>> metadataCollection, List> faceCollections, List> resizeKeyValuePairs, string sourceDirectory, string[] filteredSourceDirectoryFiles) + { + if (_Configuration.PropertiesChangedForMetadata is null) + throw new Exception($"{nameof(_Configuration.PropertiesChangedForMetadata)} is null!"); + if (_Configuration?.PropertyConfiguration is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + if (_Configuration.PropertyConfiguration.PropertiesChangedForProperty is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration.PropertiesChangedForProperty)} is null!"); + if (_Configuration.PropertiesChangedForResize is null) + throw new Exception($"{nameof(_Configuration.PropertiesChangedForResize)} is null!"); + if (_Configuration.PropertiesChangedForFaces is null) + throw new Exception($"{nameof(_Configuration.PropertiesChangedForFaces)} is null!"); + string key; + string json; + string checkFile; + int sourceDirectoryLength = sourceDirectory.Length; + int rootDirectoryLength = _Configuration.PropertyConfiguration.RootDirectory.Length; + JsonSerializerOptions writeIndentedJsonSerializerOptions = new() { WriteIndented = false }; + if (!(from l in propertyCollection where l?.Width is null select true).Any()) + { + string checkDirectory; + List>> faceCollectionsKeyValuePairs = new(); + List> propertyCollectionKeyValuePairs = new(); + List>> resizeKeyValuePairsCollections = new(); + List>>> metadataCollectionKeyValuePairs = new(); + (int level, List directories) = Property.Models.Stateless.IPath.Get(_Configuration.PropertyConfiguration.RootDirectory, sourceDirectory); + string fileName = string.Concat(string.Join(_Configuration.PropertyConfiguration.FileNameDirectorySeparator, directories), ".json"); + for (int i = 0; i < filteredSourceDirectoryFiles.Length; i++) + { + key = Property.Models.Stateless.IPath.GetRelativePath(filteredSourceDirectoryFiles[i], sourceDirectoryLength); + faceCollectionsKeyValuePairs.Add(new KeyValuePair>(key, faceCollections[i])); + propertyCollectionKeyValuePairs.Add(new KeyValuePair(key, propertyCollection[i])); + resizeKeyValuePairsCollections.Add(new KeyValuePair>(key, resizeKeyValuePairs[i])); + metadataCollectionKeyValuePairs.Add(new KeyValuePair>>(key, metadataCollection[i])); + } + if (_Metadata.AngleBracketCollection.Any()) + { + checkDirectory = Property.Models.Stateless.IPath.GetDirectory(_Metadata.AngleBracketCollection[0], level, "[{}]"); + checkFile = Path.Combine(checkDirectory, fileName); + if (File.Exists(checkFile)) + File.Move(checkFile, Path.Combine(checkDirectory, fileName)); + checkFile = Path.Combine(checkDirectory, fileName); + json = JsonSerializer.Serialize(metadataCollectionKeyValuePairs, writeIndentedJsonSerializerOptions); + _ = Property.Models.Stateless.IPath.WriteAllText(checkFile, json, compareBeforeWrite: true); + } + if (propertyLogic.AngleBracketCollection.Any()) + { + checkDirectory = Property.Models.Stateless.IPath.GetDirectory(propertyLogic.AngleBracketCollection[0], level, "[{}]"); + checkFile = Path.Combine(checkDirectory, fileName); + if (File.Exists(checkFile)) + File.Move(checkFile, Path.Combine(checkDirectory, fileName)); + checkFile = Path.Combine(checkDirectory, fileName); + json = JsonSerializer.Serialize(propertyCollectionKeyValuePairs, writeIndentedJsonSerializerOptions); + _ = Property.Models.Stateless.IPath.WriteAllText(checkFile, json, compareBeforeWrite: true); + } + if (_Resize.AngleBracketCollection.Any()) + { + checkDirectory = Property.Models.Stateless.IPath.GetDirectory(_Resize.AngleBracketCollection[0], level, "[{}]"); + checkFile = Path.Combine(checkDirectory, fileName); + if (File.Exists(checkFile)) + File.Move(checkFile, Path.Combine(checkDirectory, fileName)); + checkFile = Path.Combine(checkDirectory, fileName); + json = JsonSerializer.Serialize(resizeKeyValuePairsCollections, writeIndentedJsonSerializerOptions); + _ = Property.Models.Stateless.IPath.WriteAllText(checkFile, json, compareBeforeWrite: true); + } + if (_Configuration.LoadOrCreateThenSaveImageFacesResults.HasValue && _Configuration.LoadOrCreateThenSaveImageFacesResults.Value && _Faces.AngleBracketCollection.Any()) + { + checkDirectory = Property.Models.Stateless.IPath.GetDirectory(_Faces.AngleBracketCollection[0], level, "[{}]"); + checkFile = Path.Combine(checkDirectory, fileName); + if (File.Exists(checkFile)) + File.Move(checkFile, Path.Combine(checkDirectory, fileName)); + checkFile = Path.Combine(checkDirectory, fileName); + json = JsonSerializer.Serialize(faceCollectionsKeyValuePairs, writeIndentedJsonSerializerOptions); + _ = Property.Models.Stateless.IPath.WriteAllText(checkFile, json, compareBeforeWrite: true); + } + } + } + + private void FullDoWork(List topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> groupCollection) + { + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + if (_AppSettings.MaxDegreeOfParallelism is null) + throw new Exception($"{nameof(_AppSettings.MaxDegreeOfParallelism)} is null!"); + if (_Configuration?.PropertyConfiguration is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + if (_Configuration.PropertyConfiguration.ForcePropertyLastWriteTimeToCreationTime is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration.ForcePropertyLastWriteTimeToCreationTime)} is null!"); + if (_Configuration.LoadOrCreateThenSaveImageFacesResults is null) + throw new Exception($"{nameof(_Configuration.LoadOrCreateThenSaveImageFacesResults)} is null!"); + if (_Configuration.LoadOrCreateThenSaveDirectoryDistanceResults is null) + throw new Exception($"{nameof(_Configuration.LoadOrCreateThenSaveDirectoryDistanceResults)} is null!"); + if (_Configuration.LoadOrCreateThenSaveDistanceResults is null) + throw new Exception($"{nameof(_Configuration.LoadOrCreateThenSaveDistanceResults)} is null!"); + if (_Configuration.PropertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass)} is null!"); + if (_Configuration.PropertyConfiguration.PopulatePropertyId is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration.PopulatePropertyId)} is null!"); + if (_Configuration.PropertyConfiguration.PropertiesChangedForProperty is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration.PropertiesChangedForProperty)} is null!"); + if (_Configuration.PropertyConfiguration.WriteBitmapDataBytes is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration.WriteBitmapDataBytes)} is null!"); + int exceptionCount; + object @lock = new(); + long ticks = DateTime.Now.Ticks; + string[] filteredSourceDirectoryFiles; + List> faceCollections = new(); + List propertyCollection = new(); + PropertyLogic propertyLogic = GetPropertyLogic(); + List propertyFileInfoCollection = new(); + List> resizeKeyValuePairs = new(); + List> sourceDirectoryChanges = new(); + string propertyRoot = Property.Models.Stateless.IResult.GetResultsGroupDirectory(_Configuration.PropertyConfiguration, nameof(A_Property)); + List>> metadataCollection = new(); + foreach (string outputResolution in _Configuration.OutputResolutions) + { + _FileKeyValuePairs.Clear(); + _FilePropertiesKeyValuePairs.Clear(); + foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles, int r) in groupCollection) + { + if (!topDirectories.Any()) + continue; + _Faces.AngleBracketCollection.Clear(); + _Resize.AngleBracketCollection.Clear(); + _Metadata.AngleBracketCollection.Clear(); + propertyLogic.AngleBracketCollection.Clear(); + _FaceLandmarks.AngleBracketCollection.Clear(); + filteredSourceDirectoryFiles = (from l in sourceDirectoryFiles where !_Configuration.IgnoreExtensions.Contains(Path.GetExtension(l)) select l).ToArray(); + if (!filteredSourceDirectoryFiles.Any()) + continue; + propertyLogic.AngleBracketCollection.AddRange(Property.Models.Stateless.IResult.GetDirectoryInfoCollection(_Configuration.PropertyConfiguration, + sourceDirectory, + nameof(A_Property), + outputResolution, + includeResizeGroup: false, + includeModel: false, + includePredictorModel: false, + contentDescription: string.Empty, + singletonDescription: "Properties for each image", + collectionDescription: string.Empty)); + _Metadata.AngleBracketCollection.AddRange(Property.Models.Stateless.IResult.GetDirectoryInfoCollection(_Configuration.PropertyConfiguration, + sourceDirectory, + nameof(B_Metadata), + outputResolution, + includeResizeGroup: false, + includeModel: false, + includePredictorModel: false, + contentDescription: string.Empty, + singletonDescription: "Metadata as key value pairs", + collectionDescription: string.Empty)); + _Resize.AngleBracketCollection.AddRange(Property.Models.Stateless.IResult.GetDirectoryInfoCollection(_Configuration.PropertyConfiguration, + sourceDirectory, + nameof(C_Resize), + outputResolution, + includeResizeGroup: true, + includeModel: false, + includePredictorModel: false, + contentDescription: "Resized image", + singletonDescription: "Resize deminsions for each resolution", + collectionDescription: string.Empty)); + if (_Configuration.LoadOrCreateThenSaveImageFacesResults.HasValue && _Configuration.LoadOrCreateThenSaveImageFacesResults.Value) + _Faces.AngleBracketCollection.AddRange(Property.Models.Stateless.IResult.GetDirectoryInfoCollection(_Configuration.PropertyConfiguration, + sourceDirectory, + nameof(D_Face), + outputResolution, + includeResizeGroup: true, + includeModel: true, + includePredictorModel: true, + contentDescription: "n png file(s) for each face found", + singletonDescription: string.Empty, + collectionDescription: "For each image a json file with all faces found")); + if (_Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution)) + _FaceLandmarks.AngleBracketCollection.AddRange(Property.Models.Stateless.IResult.GetDirectoryInfoCollection(_Configuration.PropertyConfiguration, + sourceDirectory, + nameof(D2_FaceLandmarks), + outputResolution, + includeResizeGroup: true, + includeModel: true, + includePredictorModel: true, + contentDescription: "n x 2 png file(s) for each face found", + singletonDescription: string.Empty, + collectionDescription: string.Empty)); + exceptionCount = FullParallelWork(@lock, ticks, propertyLogic, outputResolution, sourceDirectoryChanges, propertyFileInfoCollection, propertyCollection, metadataCollection, resizeKeyValuePairs, faceCollections, g, sourceDirectory, r, filteredSourceDirectoryFiles, groupCollection.Count); + if (metadataCollection.Count != filteredSourceDirectoryFiles.Length || propertyCollection.Count != filteredSourceDirectoryFiles.Length || resizeKeyValuePairs.Count != filteredSourceDirectoryFiles.Length || faceCollections.Count != filteredSourceDirectoryFiles.Length) + throw new Exception("Counts don't match!"); + if (exceptionCount != 0) + _Exceptions.Add(sourceDirectory); + else + { + string key; + int rootDirectoryLength = _Configuration.PropertyConfiguration.RootDirectory.Length; + _FilePropertiesKeyValuePairs.Add(sourceDirectory, new List>()); + for (int i = 0; i < filteredSourceDirectoryFiles.Length; i++) + { + key = Property.Models.Stateless.IPath.GetRelativePath(filteredSourceDirectoryFiles[i], rootDirectoryLength); + _FileKeyValuePairs.Add(new KeyValuePair(sourceDirectory, key)); + _FilePropertiesKeyValuePairs[sourceDirectory].Add(new Tuple(key, propertyCollection[i])); + } + } + if (exceptionCount == 0 && _ArgZeroIsConfigurationRootDirectory) + WriteGroup(propertyLogic, propertyCollection, metadataCollection, faceCollections, resizeKeyValuePairs, sourceDirectory, filteredSourceDirectoryFiles); + if (exceptionCount == 0 && _Configuration.LoadOrCreateThenSaveDistanceResults.HasValue && _Configuration.LoadOrCreateThenSaveDistanceResults.Value) + _Distance.LoadOrCreateThenSaveDistanceResults(_Configuration.PropertyConfiguration, sourceDirectory, outputResolution, sourceDirectoryChanges, filteredSourceDirectoryFiles, faceCollections); + if (_Resize.AngleBracketCollection.Any()) + _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(_Resize.AngleBracketCollection[0].Replace("<>", "()")); + if (_Faces.AngleBracketCollection.Any()) + _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(_Faces.AngleBracketCollection[0].Replace("<>", "()")); + if (_FaceLandmarks.AngleBracketCollection.Any()) + _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(_FaceLandmarks.AngleBracketCollection[0].Replace("<>", "()")); + if (Directory.GetFiles(propertyRoot, "*.txt", SearchOption.TopDirectoryOnly).Any()) + { + for (int y = 0; y < int.MaxValue; y++) + { + _Log.Information("Press \"Y\" key when ready to continue or close console"); + if (Console.ReadKey().Key == ConsoleKey.Y) + break; + } + _Log.Information(". . ."); + } + } + if (_ArgZeroIsConfigurationRootDirectory && outputResolution == _Configuration.OutputResolutions[0]) + { + int loadLessThan = 7; + string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A_Property), "{}"); + PropertyCompare.Models.PropertyCompareLogic propertyCompareLogic = new(_AppSettings.MaxDegreeOfParallelism.Value, _Configuration.PropertyConfiguration); + PropertyCompare.Models.PropertyCompare[] propertyCompares = propertyCompareLogic.Get(aPropertySingletonDirectory, loadLessThan); + { + string[] lines = (from l in propertyCompares select l.GetSelect()).ToArray(); + string aPropertyCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A_Property), "[{}]"); + File.WriteAllLines(Path.Join(aPropertyCollectionDirectory, $". . . Ids - {ticks}.txt"), lines); + string json = JsonSerializer.Serialize(propertyCompares, new JsonSerializerOptions { WriteIndented = true }); + File.WriteAllText(Path.Join(aPropertyCollectionDirectory, $". . . Ids - {ticks}.nosj"), json); + } + if (!_Configuration.LoadOrCreateThenSaveImageFacesResults.Value && !_Configuration.LoadOrCreateThenSaveDirectoryDistanceResults.Value && !_Configuration.LoadOrCreateThenSaveDistanceResults.Value) + break; + if (_Exceptions.Count == 0) + { + if (_FileKeyValuePairs.Any()) + _Random.Random(_Configuration.PropertyConfiguration, _Configuration.OutputResolutions[0], _FileKeyValuePairs); + if (_IsEnvironment.Development) + continue; + G2_Identify identify = new(_Configuration); + List identifiedCollection = identify.GetIdentifiedCollection(_Configuration.PropertyConfiguration, _IsEnvironment, _People); + _People.WriteAllText(_Configuration.PropertyConfiguration, _Configuration.OutputResolutions[0], identifiedCollection); + identify.WriteAllText(_Configuration.PropertyConfiguration, _Configuration.OutputResolutions[0], identifiedCollection); + if (_Configuration.LoadOrCreateThenSaveIndex.HasValue && _Configuration.LoadOrCreateThenSaveIndex.Value && _FilePropertiesKeyValuePairs.Any()) + _Index.SetIndex(_Configuration.PropertyConfiguration, _Configuration.OutputResolutions[0], _FilePropertiesKeyValuePairs); + } + } + } + } + + private PropertyLogic GetPropertyLogic() + { + PropertyLogic result; + + + string[] verifyToSeason = Array.Empty(); + + + if (_AppSettings.MaxDegreeOfParallelism is null) + throw new Exception($"{nameof(_AppSettings.MaxDegreeOfParallelism)} is null!"); + if (_Configuration?.PropertyConfiguration is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + result = new(_AppSettings.MaxDegreeOfParallelism.Value, _Configuration.PropertyConfiguration, verifyToSeason); + return result; + } + + private void Search(string argZero) + { + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + if (_AppSettings.MaxDegreeOfParallelism is null) + throw new Exception($"{nameof(_AppSettings.MaxDegreeOfParallelism)} is null!"); + if (_Configuration?.PropertyConfiguration is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + if (_Configuration.PropertyConfiguration.ForcePropertyLastWriteTimeToCreationTime is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration.ForcePropertyLastWriteTimeToCreationTime)} is null!"); + if (_Configuration.PropertyConfiguration.IgnoreExtensions is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration.IgnoreExtensions)} is null!"); + if (_Configuration.PropertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass)} is null!"); + if (_Configuration.PropertyConfiguration.PopulatePropertyId is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration.PopulatePropertyId)} is null!"); + if (_Configuration.PropertyConfiguration.PropertiesChangedForProperty is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration.PropertiesChangedForProperty)} is null!"); + if (_Configuration.Reverse is null) + throw new Exception($"{nameof(_Configuration.Reverse)} is null!"); + if (_Configuration.PropertyConfiguration.WriteBitmapDataBytes is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration.WriteBitmapDataBytes)} is null!"); + string searchPattern = "*"; + long ticks = DateTime.Now.Ticks; + List topDirectories = new(); + PropertyLogic propertyLogic = GetPropertyLogic(); + List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> groupCollection = Property.Models.Stateless.A_Property.GetGroupCollection(argZero, searchPattern, topDirectories, _Configuration.PropertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass.Value, _Configuration.Reverse.Value); + if (_AppSettings.MaxDegreeOfParallelism.Value < 2) + ticks = LogDelta(ticks, nameof(Property.Models.Stateless.A_Property.GetGroupCollection)); + _Exceptions.AddRange(propertyLogic.DoWork(_Configuration.PropertyConfiguration, topDirectories, groupCollection, firstPass: true)); + string message = $"There were {_Exceptions.Count} exception(s) thrown! {Environment.NewLine}{string.Join(Environment.NewLine, _Exceptions)}"; + _Log.Information(message); + if (_Exceptions.Count != 0) + throw new Exception(message); + if (_AppSettings.MaxDegreeOfParallelism.Value < 2) + ticks = LogDelta(ticks, nameof(Property.Models.Stateless.A_Property.GetGroupCollection)); + groupCollection = Property.Models.Stateless.A_Property.GetGroupCollection(argZero, searchPattern, topDirectories, _Configuration.PropertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass.Value, _Configuration.Reverse.Value); + if (_AppSettings.MaxDegreeOfParallelism.Value < 2) + ticks = LogDelta(ticks, nameof(Property.Models.Stateless.A_Property.GetGroupCollection)); + FullDoWork(topDirectories, groupCollection); + } + + internal void RenameQueue() + { + if (_Configuration?.PropertyConfiguration is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + _Rename.RenameQueue(_Configuration.PropertyConfiguration); + } + +} \ No newline at end of file diff --git a/Instance/Instance.csproj b/Instance/Instance.csproj new file mode 100644 index 0000000..a8703a8 --- /dev/null +++ b/Instance/Instance.csproj @@ -0,0 +1,92 @@ + + + enable + 10.0 + enable + Exe + win-x64 + net6.0 + + + Phares.View.by.Distance.Instance + false + 5.0.402.104 + Mike Phares + Phares + true + snupkg + + + true + true + true + + + Windows + + + OSX + + + Linux + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Always + + + Always + + + Always + + + \ No newline at end of file diff --git a/Instance/Models/AppSettings.cs b/Instance/Models/AppSettings.cs new file mode 100644 index 0000000..dfb43d7 --- /dev/null +++ b/Instance/Models/AppSettings.cs @@ -0,0 +1,35 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Instance.Models; + +public class AppSettings +{ + + protected string _Company; + protected string _WorkingDirectoryName; + protected int? _MaxDegreeOfParallelism; + public string Company => _Company; + public string WorkingDirectoryName => _WorkingDirectoryName; + public int? MaxDegreeOfParallelism => _MaxDegreeOfParallelism; + + // public AppSettings() + // { + + // } + + [JsonConstructor] + public AppSettings(string company, string workingDirectoryName, int? maxDegreeOfParallelism) + { + _Company = company; + _WorkingDirectoryName = workingDirectoryName; + _MaxDegreeOfParallelism = maxDegreeOfParallelism; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/Instance/Models/Binder/AppSettings.cs b/Instance/Models/Binder/AppSettings.cs new file mode 100644 index 0000000..f10b9e7 --- /dev/null +++ b/Instance/Models/Binder/AppSettings.cs @@ -0,0 +1,26 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.Json; + +namespace View_by_Distance.Instance.Models.Binder; + +public class AppSettings +{ + + [Display(Name = "Company"), Required] public string Company { get; set; } + [Display(Name = "Working Directory Name"), Required] public string WorkingDirectoryName { get; set; } + [Display(Name = "Max Degree Of Parallelism"), Required] public int? MaxDegreeOfParallelism { get; set; } + + public AppSettings() + { + Company = string.Empty; + WorkingDirectoryName = string.Empty; + MaxDegreeOfParallelism = -1; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/Instance/Models/Binder/Configuration.cs b/Instance/Models/Binder/Configuration.cs new file mode 100644 index 0000000..e69ab67 --- /dev/null +++ b/Instance/Models/Binder/Configuration.cs @@ -0,0 +1,99 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.Json; + +namespace View_by_Distance.Instance.Models.Binder; + +public class Configuration +{ + + [Display(Name = "Check Json For Distance Results"), Required] public bool? CheckJsonForDistanceResults { get; set; } + [Display(Name = "CrossDirectory Max Items In Distance Collection"), Required] public int? CrossDirectoryMaxItemsInDistanceCollection { get; set; } + [Display(Name = "Distance Factor"), Required] public int? DistanceFactor { get; set; } + [Display(Name = "Force Metadata Last Write Time to Creation Time"), Required] public bool? ForceMetadataLastWriteTimeToCreationTime { get; set; } + [Display(Name = "Force Resize Last Write Time to Creation Time"), Required] public bool? ForceResizeLastWriteTimeToCreationTime { get; set; } + [Display(Name = "Ignore Extensions"), Required] public string[] IgnoreExtensions { get; set; } + [Display(Name = "Ignore Relative Paths"), Required] public string[] IgnoreRelativePaths { get; set; } + [Display(Name = "Load Or Create Then Save Directroy Distance Results"), Required] public bool? LoadOrCreateThenSaveDirectoryDistanceResults { get; set; } + [Display(Name = "Load Or Create Then Save Distance Results"), Required] public bool? LoadOrCreateThenSaveDistanceResults { get; set; } + [Display(Name = "Load Or Create Then Save Image Faces Results"), Required] public bool? LoadOrCreateThenSaveImageFacesResults { get; set; } + [Display(Name = "Load Or Create Then Save Index"), Required] public bool? LoadOrCreateThenSaveIndex { get; set; } + [Display(Name = "Location Confidence Factor"), Required] public int? LocationConfidenceFactor { get; set; } + [Display(Name = "Mapped Max Index"), Required] public int? MappedMaxIndex { get; set; } + [Display(Name = "Max Items In Distance Collection"), Required] public int? MaxItemsInDistanceCollection { get; set; } + [Display(Name = "Mixed Year Relative Paths"), Required] public string[] MixedYearRelativePaths { get; set; } + [Display(Name = "Model Directory"), Required] public string ModelDirectory { get; set; } + [Display(Name = "Model Name"), Required] public string ModelName { get; set; } + [Display(Name = "Num Jitters"), Required] public int? NumJitters { get; set; } + [Display(Name = "Output Extension"), Required] public string OutputExtension { get; set; } + [Display(Name = "Output Quality"), Required] public int? OutputQuality { get; set; } + [Display(Name = "Output Resolutions"), Required] public string[] OutputResolutions { get; set; } + [Display(Name = "Override For Face Images"), Required] public bool? OverrideForFaceImages { get; set; } + [Display(Name = "Override For Face Landmark Images"), Required] public bool? OverrideForFaceLandmarkImages { get; set; } + [Display(Name = "Override For Resize Images"), Required] public bool? OverrideForResizeImages { get; set; } + [Display(Name = "Padding Loops"), Required] public int? PaddingLoops { get; set; } + [Display(Name = "Predictor Model Name"), Required] public string PredictorModelName { get; set; } + [Display(Name = "Properties Changed For Distance"), Required] public bool? PropertiesChangedForDistance { get; set; } + [Display(Name = "Properties Changed For Faces"), Required] public bool? PropertiesChangedForFaces { get; set; } + [Display(Name = "Properties Changed For Index"), Required] public bool? PropertiesChangedForIndex { get; set; } + [Display(Name = "Properties Changed For Metadata"), Required] public bool? PropertiesChangedForMetadata { get; set; } + [Display(Name = "Properties Changed For Resize"), Required] public bool? PropertiesChangedForResize { get; set; } + [Display(Name = "Property Configuration"), Required] public Property.Models.Configuration? PropertyConfiguration { get; set; } + [Display(Name = "Reverse"), Required] public bool? Reverse { get; set; } + [Display(Name = "Save Face Landmark For Output Resolutions"), Required] public string[] SaveFaceLandmarkForOutputResolutions { get; set; } + [Display(Name = "Save Full Year Of Random Files"), Required] public bool? SaveFullYearOfRandomFiles { get; set; } + [Display(Name = "Save Resized Subfiles"), Required] public bool? SaveResizedSubfiles { get; set; } + [Display(Name = "Search for Abandoned Files"), Required] public bool? SearchForAbandonedFilesFull { get; set; } + [Display(Name = "Skip Search"), Required] public bool? SkipSearch { get; set; } + [Display(Name = "Test Distance Results"), Required] public bool? TestDistanceResults { get; set; } + [Display(Name = "Valid Resolutions"), Required] public string[] ValidResolutions { get; set; } + + public Configuration() + { + CheckJsonForDistanceResults = null; + CrossDirectoryMaxItemsInDistanceCollection = null; + DistanceFactor = null; + ForceMetadataLastWriteTimeToCreationTime = null; + ForceResizeLastWriteTimeToCreationTime = null; + IgnoreExtensions = Array.Empty(); + IgnoreRelativePaths = Array.Empty(); + LoadOrCreateThenSaveDirectoryDistanceResults = null; + LoadOrCreateThenSaveDistanceResults = null; + LoadOrCreateThenSaveImageFacesResults = null; + LoadOrCreateThenSaveIndex = null; + LocationConfidenceFactor = null; + MappedMaxIndex = null; + MaxItemsInDistanceCollection = null; + MixedYearRelativePaths = Array.Empty(); + ModelDirectory = string.Empty; + ModelName = string.Empty; + NumJitters = null; + OutputExtension = string.Empty; + OutputQuality = null; + OutputResolutions = Array.Empty(); + OverrideForFaceImages = null; + OverrideForFaceLandmarkImages = null; + OverrideForResizeImages = null; + PaddingLoops = null; + PredictorModelName = string.Empty; + PropertiesChangedForDistance = null; + PropertiesChangedForFaces = null; + PropertiesChangedForIndex = null; + PropertiesChangedForMetadata = null; + PropertiesChangedForResize = null; + Reverse = null; + SaveFaceLandmarkForOutputResolutions = Array.Empty(); + SaveFullYearOfRandomFiles = null; + SaveResizedSubfiles = null; + SearchForAbandonedFilesFull = null; + SkipSearch = null; + TestDistanceResults = null; + ValidResolutions = Array.Empty(); + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/Instance/Models/Configuration.cs b/Instance/Models/Configuration.cs new file mode 100644 index 0000000..facb9e1 --- /dev/null +++ b/Instance/Models/Configuration.cs @@ -0,0 +1,145 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Instance.Models; + +public class Configuration +{ + + protected readonly bool? _CheckJsonForDistanceResults; + protected readonly int? _CrossDirectoryMaxItemsInDistanceCollection; + protected readonly int? _DistanceFactor; + protected readonly bool? _ForceMetadataLastWriteTimeToCreationTime; + protected readonly bool? _ForceResizeLastWriteTimeToCreationTime; + protected readonly string[] _IgnoreExtensions; + protected readonly string[] _IgnoreRelativePaths; + protected readonly bool? _LoadOrCreateThenSaveDirectoryDistanceResults; + protected readonly bool? _LoadOrCreateThenSaveDistanceResults; + protected readonly bool? _LoadOrCreateThenSaveImageFacesResults; + protected readonly bool? _LoadOrCreateThenSaveIndex; + protected readonly int? _LocationConfidenceFactor; + protected readonly int? _MappedMaxIndex; + protected readonly int? _MaxItemsInDistanceCollection; + protected readonly string[] _MixedYearRelativePaths; + protected readonly string _ModelDirectory; + protected readonly string _ModelName; + protected readonly int? _NumJitters; + protected readonly string _OutputExtension; + protected readonly int? _OutputQuality; + protected readonly string[] _OutputResolutions; + protected readonly bool? _OverrideForFaceImages; + protected readonly bool? _OverrideForFaceLandmarkImages; + protected readonly bool? _OverrideForResizeImages; + protected readonly int? _PaddingLoops; + protected readonly string _PredictorModelName; + protected readonly bool? _PropertiesChangedForDistance; + protected readonly bool? _PropertiesChangedForFaces; + protected readonly bool? _PropertiesChangedForIndex; + protected readonly bool? _PropertiesChangedForMetadata; + protected readonly bool? _PropertiesChangedForResize; + protected Property.Models.Configuration? _PropertyConfiguration; + protected readonly bool? _Reverse; + protected readonly string[] _SaveFaceLandmarkForOutputResolutions; + protected readonly bool? _SaveFullYearOfRandomFiles; + protected readonly bool? _SaveResizedSubfiles; + protected readonly bool? _SearchForAbandonedFiles; + protected readonly bool? _SkipSearch; + protected readonly bool? _TestDistanceResults; + protected readonly string[] _ValidResolutions; + public bool? CheckJsonForDistanceResults => _CheckJsonForDistanceResults; + public int? CrossDirectoryMaxItemsInDistanceCollection => _CrossDirectoryMaxItemsInDistanceCollection; + public int? DistanceFactor => _DistanceFactor; + public bool? ForceMetadataLastWriteTimeToCreationTime => _ForceMetadataLastWriteTimeToCreationTime; + public bool? ForceResizeLastWriteTimeToCreationTime => _ForceResizeLastWriteTimeToCreationTime; + public string[] IgnoreExtensions => _IgnoreExtensions; + public string[] IgnoreRelativePaths => _IgnoreRelativePaths; + public bool? LoadOrCreateThenSaveDirectoryDistanceResults => _LoadOrCreateThenSaveDirectoryDistanceResults; + public bool? LoadOrCreateThenSaveDistanceResults => _LoadOrCreateThenSaveDistanceResults; + public bool? LoadOrCreateThenSaveImageFacesResults => _LoadOrCreateThenSaveImageFacesResults; + public bool? LoadOrCreateThenSaveIndex => _LoadOrCreateThenSaveIndex; + public int? LocationConfidenceFactor => _LocationConfidenceFactor; + public int? MappedMaxIndex => _MappedMaxIndex; + public int? MaxItemsInDistanceCollection => _MaxItemsInDistanceCollection; + public string[] MixedYearRelativePaths => _MixedYearRelativePaths; + public string ModelDirectory => _ModelDirectory; + public string ModelName => _ModelName; + public int? NumJitters => _NumJitters; + public string OutputExtension => _OutputExtension; + public int? OutputQuality => _OutputQuality; + public string[] OutputResolutions => _OutputResolutions; + public bool? OverrideForFaceImages => _OverrideForFaceImages; + public bool? OverrideForFaceLandmarkImages => _OverrideForFaceLandmarkImages; + public bool? OverrideForResizeImages => _OverrideForResizeImages; + public int? PaddingLoops => _PaddingLoops; + public string PredictorModelName => _PredictorModelName; + public bool? PropertiesChangedForDistance => _PropertiesChangedForDistance; + public bool? PropertiesChangedForFaces => _PropertiesChangedForFaces; + public bool? PropertiesChangedForIndex => _PropertiesChangedForIndex; + public bool? PropertiesChangedForMetadata => _PropertiesChangedForMetadata; + public bool? PropertiesChangedForResize => _PropertiesChangedForResize; + public Property.Models.Configuration? PropertyConfiguration => _PropertyConfiguration; + public bool? Reverse => _Reverse; + public string[] SaveFaceLandmarkForOutputResolutions => _SaveFaceLandmarkForOutputResolutions; + public bool? SaveFullYearOfRandomFiles => _SaveFullYearOfRandomFiles; + public bool? SaveResizedSubfiles => _SaveResizedSubfiles; + public bool? SearchForAbandonedFilesFull => _SearchForAbandonedFiles; + public bool? SkipSearch => _SkipSearch; + public bool? TestDistanceResults => _TestDistanceResults; + public string[] ValidResolutions => _ValidResolutions; + + [JsonConstructor] + public Configuration(bool? checkJsonForDistanceResults, int? crossDirectoryMaxItemsInDistanceCollection, int? distanceFactor, bool? forceMetadataLastWriteTimeToCreationTime, bool? forceResizeLastWriteTimeToCreationTime, string[] ignoreExtensions, string[] ignoreRelativePaths, bool? loadOrCreateThenSaveDirectoryDistanceResults, bool? loadOrCreateThenSaveDistanceResults, bool? loadOrCreateThenSaveImageFacesResults, bool? loadOrCreateThenSaveIndex, int? locationConfidenceFactor, int? mappedMaxIndex, int? maxItemsInDistanceCollection, string[] mixedYearRelativePaths, string modelDirectory, string modelName, int? numJitters, string outputExtension, int? outputQuality, string[] outputResolutions, bool? overrideForFaceImages, bool? overrideForFaceLandmarkImages, bool? overrideForResizeImages, int? paddingLoops, string predictorModelName, bool? propertiesChangedForDistance, bool? propertiesChangedForFaces, bool? propertiesChangedForIndex, bool? propertiesChangedForMetadata, bool? propertiesChangedForResize, Property.Models.Configuration? propertyConfiguration, bool? reverse, string[] saveFaceLandmarkForOutputResolutions, bool? saveFullYearOfRandomFiles, bool? saveResizedSubfiles, bool? searchForAbandonedFilesFull, bool? skipSearch, bool? testDistanceResults, string[] validResolutions) + { + _CheckJsonForDistanceResults = checkJsonForDistanceResults; + _CrossDirectoryMaxItemsInDistanceCollection = crossDirectoryMaxItemsInDistanceCollection; + _DistanceFactor = distanceFactor; + _ForceMetadataLastWriteTimeToCreationTime = forceMetadataLastWriteTimeToCreationTime; + _ForceResizeLastWriteTimeToCreationTime = forceResizeLastWriteTimeToCreationTime; + _IgnoreExtensions = ignoreExtensions; + _IgnoreRelativePaths = ignoreRelativePaths; + _LoadOrCreateThenSaveDirectoryDistanceResults = loadOrCreateThenSaveDirectoryDistanceResults; + _LoadOrCreateThenSaveDistanceResults = loadOrCreateThenSaveDistanceResults; + _LoadOrCreateThenSaveImageFacesResults = loadOrCreateThenSaveImageFacesResults; + _LoadOrCreateThenSaveIndex = loadOrCreateThenSaveIndex; + _LocationConfidenceFactor = locationConfidenceFactor; + _MappedMaxIndex = mappedMaxIndex; + _MaxItemsInDistanceCollection = maxItemsInDistanceCollection; + _MixedYearRelativePaths = mixedYearRelativePaths; + _ModelDirectory = modelDirectory; + _ModelName = modelName; + _NumJitters = numJitters; + _OutputExtension = outputExtension; + _OutputQuality = outputQuality; + _OutputResolutions = outputResolutions; + _OverrideForFaceImages = overrideForFaceImages; + _OverrideForFaceLandmarkImages = overrideForFaceLandmarkImages; + _OverrideForResizeImages = overrideForResizeImages; + _PaddingLoops = paddingLoops; + _PredictorModelName = predictorModelName; + _PropertiesChangedForDistance = propertiesChangedForDistance; + _PropertiesChangedForFaces = propertiesChangedForFaces; + _PropertiesChangedForIndex = propertiesChangedForIndex; + _PropertiesChangedForMetadata = propertiesChangedForMetadata; + _PropertiesChangedForResize = propertiesChangedForResize; + _PropertyConfiguration = propertyConfiguration; + _Reverse = reverse; + _SaveFaceLandmarkForOutputResolutions = saveFaceLandmarkForOutputResolutions; + _SaveFullYearOfRandomFiles = saveFullYearOfRandomFiles; + _SaveResizedSubfiles = saveResizedSubfiles; + _SearchForAbandonedFiles = searchForAbandonedFilesFull; + _SkipSearch = skipSearch; + _TestDistanceResults = testDistanceResults; + _ValidResolutions = validResolutions; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + + public void Set(Property.Models.Configuration propertyConfiguration) => _PropertyConfiguration = propertyConfiguration; + + public void Update() => _PropertyConfiguration?.Update(); + +} \ No newline at end of file diff --git a/Instance/Models/Stateless/AppSettings.cs b/Instance/Models/Stateless/AppSettings.cs new file mode 100644 index 0000000..43f093e --- /dev/null +++ b/Instance/Models/Stateless/AppSettings.cs @@ -0,0 +1,40 @@ +using Microsoft.Extensions.Configuration; +using System.Text.Json; + +namespace View_by_Distance.Instance.Models.Stateless; + +public abstract class AppSettings +{ + + public static Models.AppSettings Get(IConfigurationRoot configurationRoot) + { + Models.AppSettings? result; + Binder.AppSettings appSettings = configurationRoot.Get(); + string json = JsonSerializer.Serialize(appSettings, new JsonSerializerOptions() { WriteIndented = true }); + result = JsonSerializer.Deserialize(json); + if (result is null) + throw new Exception(json); + if (string.IsNullOrEmpty(result.Company)) + throw new Exception(json); + string jsonThis = result.ToString(); + if (jsonThis != json) + { + int? check = null; + int min = new int[] { json.Length, jsonThis.Length }.Min(); + for (int i = 0; i < min; i++) + { + if (json[i] == jsonThis[i]) + continue; + check = i; + break; + } + if (check is null) + throw new Exception(); + string a = json[..check.Value].Split(',')[^1]; + string b = json[check.Value..].Split(',')[0]; + throw new Exception($"{a}{b}"); + } + return result; + } + +} \ No newline at end of file diff --git a/Instance/Models/Stateless/Configuration.cs b/Instance/Models/Stateless/Configuration.cs new file mode 100644 index 0000000..96e636c --- /dev/null +++ b/Instance/Models/Stateless/Configuration.cs @@ -0,0 +1,44 @@ +using Microsoft.Extensions.Configuration; +using Phares.Shared; +using System.Text.Json; + +namespace View_by_Distance.Instance.Models.Stateless; + +public abstract class Configuration +{ + + public static Models.Configuration Get(IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, string workingDirectory, Property.Models.Configuration propertyConfiguration) + { + Models.Configuration? result; + string environmentName = IsEnvironment.GetEnvironmentName(isEnvironment); + string section = string.Concat(environmentName, ":", nameof(Binder.Configuration)); + IConfigurationSection configurationSection = configurationRoot.GetSection(section); + Binder.Configuration configuration = configurationSection.Get(); + string json = JsonSerializer.Serialize(configuration, new JsonSerializerOptions() { WriteIndented = true }); + result = JsonSerializer.Deserialize(json); + if (result is null) + throw new Exception(json); + string jsonThis = result.ToString(); + result.Set(propertyConfiguration); + result.Update(); + if (jsonThis != json) + { + int? check = null; + int min = new int[] { json.Length, jsonThis.Length }.Min(); + for (int i = 0; i < min; i++) + { + if (json[i] == jsonThis[i]) + continue; + check = i; + break; + } + if (check is null) + throw new Exception(); + string a = json[..check.Value].Split(',')[^1]; + string b = json[check.Value..].Split(',')[0]; + throw new Exception($"{a}{b}"); + } + return result; + } + +} \ No newline at end of file diff --git a/Instance/Models/Stateless/SerilogExtensionMethods.cs b/Instance/Models/Stateless/SerilogExtensionMethods.cs new file mode 100644 index 0000000..07c754c --- /dev/null +++ b/Instance/Models/Stateless/SerilogExtensionMethods.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Instance.Models.Stateless; + +public static class SerilogExtensionMethods +{ + + internal static void Warn(this Serilog.ILogger log, string messageTemplate) => log.Warning(messageTemplate); + + internal static void Info(this Serilog.ILogger log, string messageTemplate) => log.Information(messageTemplate); + +} \ No newline at end of file diff --git a/Instance/Models/_A2_People.cs b/Instance/Models/_A2_People.cs new file mode 100644 index 0000000..fbcb6c0 --- /dev/null +++ b/Instance/Models/_A2_People.cs @@ -0,0 +1,79 @@ +using System.Text.Json; +using View_by_Distance.Property.Models; +using View_by_Distance.Shared.Models; + +namespace View_by_Distance.Instance.Models; + +/// +// ? +/// +internal class A2_People +{ + + private readonly Serilog.ILogger? _Log; + private readonly Configuration _Configuration; + private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions; + + internal A2_People(Configuration configuration) + { + _Configuration = configuration; + _Log = Serilog.Log.ForContext(); + _WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true }; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + + internal void WriteAllText(Property.Models.Configuration configuration, string outputResolution, List identifiedCollection) + { + string key; + string json; + string jsonFile; + FileInfo fileInfo; + string[] segments; + string directoryFullName; + Dictionary> keyValuePairs = new(); + string hPeopleCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A2_People), "[]"); + string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "{}"); + foreach (G2_Identify identified in identifiedCollection) + { + fileInfo = new FileInfo(string.Concat(aPropertySingletonDirectory, identified.RelativePath)); + if (fileInfo?.Directory is null || !fileInfo.Directory.Exists || fileInfo.Exists) + continue; + key = string.Concat(identified.ParentDirectoryName, '|', identified.Person); + if (!keyValuePairs.ContainsKey(key)) + keyValuePairs.Add(key, new List()); + keyValuePairs[key].Add(identified); + } + foreach (KeyValuePair> keyValuePair in keyValuePairs) + { + segments = keyValuePair.Key.Split('|'); + directoryFullName = Path.Combine(hPeopleCollectionDirectory, segments[0]); + if (!Directory.Exists(directoryFullName)) + _ = Directory.CreateDirectory(directoryFullName); + jsonFile = Path.Combine(directoryFullName, $"{segments[1]}.json"); + json = JsonSerializer.Serialize(keyValuePair.Value, _WriteIndentedJsonSerializerOptions); + if (!Property.Models.Stateless.IPath.WriteAllText(jsonFile, json, compareBeforeWrite: true)) + continue; + } + } + + internal Person[] GetPeople(Property.Models.Configuration configuration) + { + Person[] results; + if (_Configuration?.PropertyConfiguration is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + string rootDirectory = _Configuration.PropertyConfiguration.RootDirectory; + string peopleRootDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A2_People)); + string? rootResultsDirectory = Path.GetDirectoryName(Path.GetDirectoryName(peopleRootDirectory)); + if (rootResultsDirectory is null) + throw new Exception(); + Storage storage = new(rootDirectory, rootResultsDirectory, peopleRootDirectory); + results = Shared.Models.Stateless.Methods.IPerson.GetPeople(storage); + return results.ToArray(); + } + +} \ No newline at end of file diff --git a/Instance/Models/_D2_FaceLandmark.cs b/Instance/Models/_D2_FaceLandmark.cs new file mode 100644 index 0000000..6a329b7 --- /dev/null +++ b/Instance/Models/_D2_FaceLandmark.cs @@ -0,0 +1,161 @@ +using FaceRecognitionDotNet; +using System.Drawing; +using System.Text.Json; +using View_by_Distance.Metadata.Models; +using View_by_Distance.Property.Models; +using View_by_Distance.Resize.Models; + +namespace View_by_Distance.Instance.Models; + +/// +// *.png +/// +internal class D2_FaceLandmarks +{ + + internal List AngleBracketCollection { get; } + + private readonly Serilog.ILogger? _Log; + private readonly Configuration _Configuration; + + internal D2_FaceLandmarks(Configuration configuration) + { + _Configuration = configuration; + AngleBracketCollection = new List(); + _Log = Serilog.Log.ForContext(); + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +#pragma warning disable CA1416 + + private static Bitmap RotateBitmap(System.Drawing.Image image, float angle) + { + Bitmap result; + Bitmap bitmap = new(image); + result = D_Face.RotateBitmap(bitmap, angle); + if (bitmap is not null) + bitmap.Dispose(); + return result; + } + + private static void SaveFaceLandmarkImages(List faceCollections, List imageFiles, int pointSize, FileInfo resizedFileInfo) + { + int x; + int y; + D_Face face; + int width; + int height; + string imageFileFullName; + Bitmap rotated; + string rotatedImageFileFullName; + Shared.Models.FacePoint[] facePoints; + for (int i = 0; i < faceCollections.Count; i++) + { + if (!faceCollections[i].Populated) + continue; + face = faceCollections[i]; + imageFileFullName = imageFiles[i][0]; + rotatedImageFileFullName = imageFiles[i][1]; + try + { + using (System.Drawing.Image image = System.Drawing.Image.FromFile(resizedFileInfo.FullName)) + { + using Graphics graphic = Graphics.FromImage(image); + if (face.FaceLandmarks is null || !face.FaceLandmarks.Any()) + { + width = face.Location.Right - face.Location.Left; + height = face.Location.Bottom - face.Location.Top; + graphic.DrawEllipse(Pens.Red, face.Location.Left, face.Location.Top, width, height); + } + else + { + foreach (KeyValuePair keyValuePair in face.FaceLandmarks) + { + facePoints = keyValuePair.Value.ToArray(); + foreach (Shared.Models.FacePoint facePoint in facePoints) + graphic.DrawEllipse(Pens.GreenYellow, face.Location.Left + facePoint.X - pointSize, face.Location.Top + facePoint.Y - pointSize, pointSize * 2, pointSize * 2); + if (keyValuePair.Key == FacePart.Chin.ToString()) + continue; + if (facePoints.Length < 3) + continue; + x = (int)(from l in facePoints select l.X).Average(); + y = (int)(from l in facePoints select l.Y).Average(); + graphic.DrawEllipse(Pens.Purple, face.Location.Left + x - pointSize, face.Location.Top + y - pointSize, pointSize * 2, pointSize * 2); + } + } + image.Save(imageFileFullName, System.Drawing.Imaging.ImageFormat.Png); + } + if (face.α.HasValue) + { + using System.Drawing.Image image = System.Drawing.Image.FromFile(resizedFileInfo.FullName); + rotated = RotateBitmap(image, (float)face.α.Value); + if (rotated is not null) + { + rotated.Save(rotatedImageFileFullName, System.Drawing.Imaging.ImageFormat.Png); + rotated.Dispose(); + } + } + } + catch (Exception) { } + } + } + +#pragma warning restore CA1416 + + internal void SaveFaceLandmarkImages(List> subFileTuples, List parseExceptions, string relativePath, string fileNameWithoutExtension, FileInfo resizedFileInfo, List faceCollections) + { + FileInfo fileInfo; + bool check = false; + string parentCheck; + const int pointSize = 2; + FileInfo rotatedFileInfo; + long ticks = DateTime.Now.Ticks; + List imageFiles = new(); + string facesDirectory = Path.Combine(AngleBracketCollection[0].Replace("<>", "()"), fileNameWithoutExtension); + string[] changesFrom = new string[] { nameof(A_Property), nameof(B_Metadata), nameof(C_Resize), nameof(D_Face) }; + List dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); + if (!Directory.Exists(facesDirectory)) + _ = Directory.CreateDirectory(facesDirectory); + for (int i = 0; i < faceCollections.Count; i++) + { + if (!faceCollections[i].Populated) + { + imageFiles.Add(Array.Empty()); + continue; + } + fileInfo = new FileInfo(Path.Combine(facesDirectory, $"{i} - {fileNameWithoutExtension}.png")); + if (!fileInfo.Exists) + { + if (fileInfo.Directory?.Parent is null) + throw new Exception(); + parentCheck = Path.Combine(fileInfo.Directory.Parent.FullName, fileInfo.Name); + if (File.Exists(parentCheck)) + File.Delete(parentCheck); + } + if (string.IsNullOrEmpty(fileInfo.DirectoryName)) + continue; + rotatedFileInfo = new FileInfo(Path.Combine(fileInfo.DirectoryName, string.Concat(Path.GetFileNameWithoutExtension(fileInfo.FullName), " - ", i, " - R", Path.GetExtension(fileInfo.FullName)))); + imageFiles.Add(new string[] { fileInfo.FullName, rotatedFileInfo.FullName }); + if (check) + continue; + if (_Configuration.OverrideForFaceLandmarkImages is null) + check = false; + else if (_Configuration.OverrideForFaceLandmarkImages.Value) + check = true; + else if (!fileInfo.Exists) + check = true; + else if (!rotatedFileInfo.Exists) + check = true; + else if (dateTimes.Any() && dateTimes.Max() > fileInfo.LastWriteTime) + check = true; + } + if (check) + SaveFaceLandmarkImages(faceCollections, imageFiles, pointSize, resizedFileInfo); + } + +} \ No newline at end of file diff --git a/Instance/Models/_D_Face.cs b/Instance/Models/_D_Face.cs new file mode 100644 index 0000000..fa46b6c --- /dev/null +++ b/Instance/Models/_D_Face.cs @@ -0,0 +1,498 @@ +using FaceRecognitionDotNet; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Text.Json; +using System.Text.Json.Serialization; +using View_by_Distance.Metadata.Models; +using View_by_Distance.Property.Models; +using View_by_Distance.Resize.Models; +using View_by_Distance.Shared.Models; +using View_by_Distance.Shared.Models.Methods; + +namespace View_by_Distance.Instance.Models; + +/// +// List +/// +public class D_Face : Shared.Models.Properties.IFace, IFace +{ + + internal List AngleBracketCollection { get; } + + private readonly Model _Model; + private readonly string _ArgZero; + private readonly Serilog.ILogger? _Log; + private readonly ModelParameter _ModelParameter; + private readonly PredictorModel _PredictorModel; + private readonly Configuration _Configuration; + private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions; + + protected double? _Α; + protected DateTime _DateTime; + protected Shared.Models.FaceEncoding _FaceEncoding; + protected Dictionary _FaceLandmarks; + protected Shared.Models.Location _Location; + protected int? _LocationIndex; + protected OutputResolution _OutputResolution; + protected bool _Populated; + protected string _RelativePath; + public double? α => _Α; + public DateTime DateTime => _DateTime; + public Shared.Models.FaceEncoding FaceEncoding => _FaceEncoding; + public Dictionary FaceLandmarks => _FaceLandmarks; + public OutputResolution OutputResolution => _OutputResolution; + public Shared.Models.Location Location => _Location; + public int? LocationIndex => _LocationIndex; + public bool Populated => _Populated; + public string RelativePath => _RelativePath; + +#nullable disable + [JsonConstructor] + public D_Face(double? α, DateTime dateTime, Shared.Models.FaceEncoding faceEncoding, Dictionary faceLandmarks, Shared.Models.Location location, int? locationIndex, OutputResolution outputResolution, bool populated, string relativePath) + { + _Α = α; + _DateTime = dateTime; + _FaceEncoding = faceEncoding; + _FaceLandmarks = faceLandmarks; + _Location = location; + _LocationIndex = locationIndex; + _OutputResolution = outputResolution; + _Populated = populated; + _RelativePath = relativePath; + } + + internal D_Face(Configuration configuration, string argZero, Model model, ModelParameter modelParameter, PredictorModel predictorModel) + { + _Model = model; + _ArgZero = argZero; + _Configuration = configuration; + _ModelParameter = modelParameter; + _PredictorModel = predictorModel; + AngleBracketCollection = new List(); + _Log = Serilog.Log.ForContext(); + _WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true }; + } + + private D_Face(Shared.Models.Location location) + { + _Α = α; + _DateTime = DateTime.MinValue; + _FaceEncoding = null; + _FaceLandmarks = null; + _OutputResolution = null; + _Location = location; + _LocationIndex = null; + _Populated = false; + _RelativePath = string.Empty; + } + + private D_Face() + { + _Α = α; + _DateTime = DateTime.MinValue; + _FaceEncoding = null; + _FaceLandmarks = null; + _OutputResolution = null; + _Location = null; + _LocationIndex = null; + _Populated = false; + _RelativePath = string.Empty; + } + + private D_Face(A_Property property, int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation, string relativePath, int? i, Shared.Models.Location location) + { + DateTime?[] dateTimes; + dateTimes = new DateTime?[] { property.CreationTime, property.LastWriteTime, property.DateTime, property.DateTimeDigitized, property.DateTimeOriginal, property.GPSDateStamp }; + _DateTime = (from l in dateTimes where l.HasValue select l.Value).Min(); + _FaceLandmarks = new Dictionary(); + _OutputResolution = new(outputResolutionHeight, outputResolutionOrientation, outputResolutionWidth); + _Location = location; + _LocationIndex = i; + _Populated = false; + _RelativePath = relativePath; + } + + private D_Face(int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation, Shared.Models.Properties.IFace face) + { + _Α = face.α; + _DateTime = face.DateTime; + _FaceEncoding = face.FaceEncoding; + _FaceLandmarks = face.FaceLandmarks; + _OutputResolution = new(outputResolutionHeight, outputResolutionOrientation, outputResolutionWidth); + _Location = face.Location; + _LocationIndex = face.LocationIndex; + _Populated = face.Populated; + _RelativePath = face.RelativePath; + } + + private static void GetPointBounds(PointF[] points, out float xmin, out float xmax, out float ymin, out float ymax) + { + xmin = points[0].X; + xmax = xmin; + ymin = points[0].Y; + ymax = ymin; + foreach (PointF point in points) + { + if (xmin > point.X) + xmin = point.X; + if (xmax < point.X) + xmax = point.X; + if (ymin > point.Y) + ymin = point.Y; + if (ymax < point.Y) + ymax = point.Y; + } + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +#pragma warning disable CA1416 + + internal static Bitmap RotateBitmap(Bitmap bitmap, float angle) + { + Bitmap result; +#if Linux + throw new Exception("Built on Linux!"); +#elif OSX + throw new Exception("Built on macOS!"); +#elif Windows + // Make a Matrix to represent rotation + // by this angle. + Matrix rotate_at_origin = new(); + rotate_at_origin.Rotate(angle); + + // Rotate the image's corners to see how big + // it will be after rotation. + PointF[] points = + { + new PointF(0, 0), + new PointF(bitmap.Width, 0), + new PointF(bitmap.Width, bitmap.Height), + new PointF(0, bitmap.Height), + }; + rotate_at_origin.TransformPoints(points); + float xmin, xmax, ymin, ymax; + GetPointBounds(points, out xmin, out xmax, out ymin, out ymax); + + // Make a bitmap to hold the rotated result. + int wid = (int)Math.Round(xmax - xmin); + int hgt = (int)Math.Round(ymax - ymin); + result = new Bitmap(wid, hgt); + + // Create the real rotation transformation. + Matrix rotate_at_center = new(); + rotate_at_center.RotateAt(angle, + new PointF(wid / 2f, hgt / 2f)); + + // Draw the image onto the new bitmap rotated. + using (Graphics gr = Graphics.FromImage(result)) + { + // Use smooth image interpolation. + gr.InterpolationMode = InterpolationMode.High; + + // Clear with the color in the image's upper left corner. + gr.Clear(bitmap.GetPixel(0, 0)); + + // For debugging. (It's easier to see the background.) + // gr.Clear(Color.LightBlue); + + // Set up the transformation to rotate. + gr.Transform = rotate_at_center; + + // Draw the image centered on the bitmap. + int x = (wid - bitmap.Width) / 2; + int y = (hgt - bitmap.Height) / 2; + gr.DrawImage(bitmap, x, y); + } +#endif + // Return the result bitmap. + return result; + } + + private static void SaveFaces(List faceCollection, FileInfo resizedFileInfo, List imageFiles) + { + int width; + int height; + Graphics graphics; + Rectangle rectangle; + Bitmap preRotated; + Shared.Models.Location location; + using Bitmap source = new(resizedFileInfo.FullName); + for (int i = 0; i < faceCollection.Count; i++) + { + if (!faceCollection[i].Populated || faceCollection[i]?.Location is null) + continue; + location = new Shared.Models.Location(faceCollection[i].Location.Confidence, + faceCollection[i].Location.Bottom, + faceCollection[i].Location.Left, + faceCollection[i].Location.Right, + faceCollection[i].Location.Top); + width = location.Right - location.Left; + height = location.Bottom - location.Top; + rectangle = new Rectangle(location.Left, location.Top, width, height); + using (preRotated = new(width, height)) + { + using (graphics = Graphics.FromImage(preRotated)) + graphics.DrawImage(source, new Rectangle(0, 0, width, height), rectangle, GraphicsUnit.Pixel); + preRotated.Save(imageFiles[i], System.Drawing.Imaging.ImageFormat.Png); + } + } + } + + private List GetFaces(FileInfo resizedFileInfo, string relativePath, string fileNameWithoutExtension, A_Property property, int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation, string facesDirectory) + { + List results = new(); + if (_Configuration.PaddingLoops is null) + throw new Exception(); + if (_Configuration.NumJitters is null) + throw new Exception(); + FaceRecognitionDotNet.Location[] locations; + FaceRecognitionDotNet.Image unknownImage = null; + if (resizedFileInfo.Exists) + { + try + { unknownImage = FaceRecognition.LoadImageFile(resizedFileInfo.FullName); } + catch (Exception) { } + } + if (unknownImage is null) + results.Add(new D_Face(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, relativePath, i: null, location: null)); + else + { + FaceRecognition faceRecognition = FaceRecognition.Create(_ModelParameter); + locations = faceRecognition.FaceLocations(unknownImage, numberOfTimesToUpsample: 1, _Model).ToArray(); + if (!locations.Any()) + results.Add(new D_Face(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, relativePath, i: null, location: null)); + else + { + double? α; + int width; + int height; + int padding; + int leftEyeX; + int leftEyeY; + int rightEyeX; + int rightEyeY; + string faceFile; + Graphics graphics; + D_Face face = null; + Rectangle rectangle; + double[] rawEncoding; + Bitmap rotated; + Bitmap preRotated; + FaceRecognitionDotNet.Image knownImage; + FaceRecognitionDotNet.Image rotatedImage; + Shared.Models.Location location; + FaceRecognitionDotNet.FaceEncoding[] faceEncodings; + IEnumerable facePoints; + Shared.Models.FaceEncoding faceEncoding; + IDictionary>[] faceLandmarks; + using Bitmap source = unknownImage.ToBitmap(); + padding = (int)((source.Width + source.Height) / 2 * .01); + for (int i = 0; i < locations.Length; i++) + { + for (int p = 0; p <= _Configuration.PaddingLoops.Value; p++) + { + //Location(double confidence, int bottom, int left, int right, int top) + location = new(locations[i].Confidence, + locations[i].Bottom + (padding * p), + locations[i].Left - (padding * p), + locations[i].Right + (padding * p), + locations[i].Top - (padding * p)); + face = new D_Face(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, relativePath, i, location); + width = location.Right - location.Left; + height = location.Bottom - location.Top; + rectangle = new Rectangle(location.Left, location.Top, width, height); + using (preRotated = new Bitmap(width, height)) + { + using (graphics = Graphics.FromImage(preRotated)) + graphics.DrawImage(source, new Rectangle(0, 0, width, height), rectangle, GraphicsUnit.Pixel); + // source.Save(Path.Combine(_Configuration.RootDirectory, "source.jpg")); + // preRotated.Save(Path.Combine(_Configuration.RootDirectory, $"{p} - preRotated.jpg")); + using (knownImage = FaceRecognition.LoadImage(preRotated)) + faceLandmarks = faceRecognition.FaceLandmark(knownImage, faceLocations: null, _PredictorModel, _Model).ToArray(); + if (faceLandmarks.Length == 0 && p < _Configuration.PaddingLoops.Value) + continue; + else if (faceLandmarks.Length != 1) + continue; + foreach (KeyValuePair> keyValuePair in faceLandmarks[0]) + face.FaceLandmarks.Add(keyValuePair.Key.ToString(), (from l in keyValuePair.Value select new Shared.Models.FacePoint(l.Index, l.Point.X, l.Point.Y)).ToArray()); + if (!faceLandmarks[0].ContainsKey(FacePart.LeftEye) || !faceLandmarks[0].ContainsKey(FacePart.RightEye)) + continue; + facePoints = faceLandmarks[0][FacePart.LeftEye]; + leftEyeX = (int)(from l in facePoints select l.Point.X).Average(); + leftEyeY = (int)(from l in facePoints select l.Point.Y).Average(); + facePoints = faceLandmarks[0][FacePart.RightEye]; + rightEyeX = (int)(from l in facePoints select l.Point.X).Average(); + rightEyeY = (int)(from l in facePoints select l.Point.Y).Average(); + α = Shared.Models.Stateless.Methods.IFace.Getα(rightEyeX, leftEyeX, rightEyeY, leftEyeY); + using (rotated = RotateBitmap(preRotated, (float)α.Value)) + { + // rotated.Save(Path.Combine(_Configuration.RootDirectory, $"{p} - rotated.jpg")); + using (rotatedImage = FaceRecognition.LoadImage(rotated)) + faceEncodings = faceRecognition.FaceEncodings(rotatedImage, knownFaceLocation: null, _Configuration.NumJitters.Value, _PredictorModel, _Model).ToArray(); + if (faceEncodings.Length == 0 && p < _Configuration.PaddingLoops.Value) + continue; + else if (faceEncodings.Length != 1) + continue; + rawEncoding = faceEncodings[0].GetRawEncoding(); + faceEncoding = new(rawEncoding, faceEncodings[0].Size); + face.Update(α, faceEncoding, populated: true); + } + faceFile = Path.Combine(facesDirectory, $"{i} - {fileNameWithoutExtension}.png"); + preRotated.Save(faceFile, System.Drawing.Imaging.ImageFormat.Png); + results.Add(face); + } + if (face.Populated) + break; + } + if (face is null || !face.Populated) + { + location = new(locations[i].Confidence, + locations[i].Bottom, + locations[i].Left, + locations[i].Right, + locations[i].Top); + face = new D_Face(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, relativePath, i, location); + results.Add(face); + } + } + } + unknownImage.Dispose(); + faceRecognition.Dispose(); + } + if (!results.Any()) + throw new Exception(); + return results; + } + +#pragma warning restore CA1416 + + private void Update(double? α, Shared.Models.FaceEncoding faceEncoding, bool populated) + { + _Α = α; + _FaceEncoding = faceEncoding; + _Populated = populated; + } + + internal List GetFaces(Property.Models.Configuration configuration, string outputResolution, List> subFileTuples, List parseExceptions, string relativePath, string fileNameWithoutExtension, A_Property property, FileInfo resizedFileInfo, int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation) + { + List results; + if (_Configuration.PropertiesChangedForFaces is null) + throw new Exception(); + string json; + D_Face face; + bool checkForOutputResolutionChange = false; + string[] changesFrom = new string[] { nameof(A_Property), nameof(B_Metadata), nameof(C_Resize) }; + string facesDirectory = Path.Combine(AngleBracketCollection[0].Replace("<>", "()"), fileNameWithoutExtension); + List dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); + FileInfo fileInfo = new(Path.Combine(AngleBracketCollection[0].Replace("<>", "[]"), $"{fileNameWithoutExtension}.json")); + if (!fileInfo.Exists) + { + if (fileInfo.Directory?.Parent is null) + throw new Exception(); + string parentCheck = Path.Combine(fileInfo.Directory.Parent.FullName, fileInfo.Name); + if (File.Exists(parentCheck)) + File.Delete(parentCheck); + } + if (!Directory.Exists(facesDirectory)) + _ = Directory.CreateDirectory(facesDirectory); + if (_Configuration.PropertiesChangedForFaces.Value) + results = null; + else if (!fileInfo.Exists) + results = null; + else if (dateTimes.Any() && dateTimes.Max() > fileInfo.LastWriteTime) + results = null; + else + { + json = Shared.Models.Stateless.Methods.IFace.GetJson(fileInfo.FullName); + try + { + results = JsonSerializer.Deserialize>(json); + for (int i = 0; i < results.Count; i++) + { + face = results[i]; + if (face.OutputResolution is not null) + continue; + if (!checkForOutputResolutionChange) + checkForOutputResolutionChange = true; + results[i] = new(outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, face); + } + subFileTuples.Add(new Tuple(nameof(D_Face), fileInfo.LastWriteTime)); + } + catch (Exception) + { + results = null; + parseExceptions.Add(nameof(D_Face)); + } + } + if (results is not null && checkForOutputResolutionChange) + { + json = JsonSerializer.Serialize(results, _WriteIndentedJsonSerializerOptions); + if (Property.Models.Stateless.IPath.WriteAllText(fileInfo.FullName, json, compareBeforeWrite: true)) + File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime); + } + else if (results is null) + { + results = GetFaces(resizedFileInfo, relativePath, fileNameWithoutExtension, property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, facesDirectory); + json = JsonSerializer.Serialize(results, _WriteIndentedJsonSerializerOptions); + if (Property.Models.Stateless.IPath.WriteAllText(fileInfo.FullName, json, compareBeforeWrite: true)) + subFileTuples.Add(new Tuple(nameof(D_Face), DateTime.Now)); + } + return results; + } + + internal void SaveFaces(Property.Models.Configuration configuration, List> subFileTuples, List parseExceptions, string relativePath, string fileNameWithoutExtension, FileInfo resizedFileInfo, List faceCollection) + { + if (_Configuration.OverrideForFaceImages is null) + throw new Exception(); + FileInfo fileInfo; + bool check = false; + string parentCheck; + List imageFiles = new(); + string[] changesFrom = new string[] { nameof(A_Property), nameof(B_Metadata), nameof(C_Resize) }; + string facesDirectory = Path.Combine(AngleBracketCollection[0].Replace("<>", "()"), fileNameWithoutExtension); + List dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); + bool facesDirectoryExisted = Directory.Exists(facesDirectory); + if (!facesDirectoryExisted) + _ = Directory.CreateDirectory(facesDirectory); + for (int i = 0; i < faceCollection.Count; i++) + { + if (!faceCollection[i].Populated || faceCollection[i]?.Location is null) + { + imageFiles.Add(string.Empty); + continue; + } + fileInfo = new FileInfo(Path.Combine(facesDirectory, $"{i} - {fileNameWithoutExtension}.png")); + if (!fileInfo.Exists) + { + if (fileInfo.Directory?.Parent is null) + throw new Exception(); + parentCheck = Path.Combine(fileInfo.Directory.Parent.FullName, fileInfo.Name); + if (File.Exists(parentCheck)) + File.Delete(parentCheck); + } + imageFiles.Add(fileInfo.FullName); + if (_Configuration.OverrideForFaceImages.Value) + check = true; + else if (!fileInfo.Exists) + check = true; + else if (dateTimes.Any() && dateTimes.Max() > fileInfo.LastWriteTime) + check = true; + } + if (check) + SaveFaces(faceCollection, resizedFileInfo, imageFiles); + } + + double Shared.Models.Stateless.Methods.IFace.TestStatic_Getα(int x1, int x2, int y1, int y2) => throw new NotImplementedException(); + + string Shared.Models.Stateless.Methods.IFace.TestStatic_GetJson(string jsonFileFullName) => throw new NotImplementedException(); + + Face Shared.Models.Stateless.Methods.IFace.TestStatic_GetFace(string jsonFileFullName) => throw new NotImplementedException(); + + Face[] Shared.Models.Stateless.Methods.IFace.TestStatic_GetFaces(string jsonFileFullName) => throw new NotImplementedException(); + +} \ No newline at end of file diff --git a/Instance/Models/_E2_Navigate.cs b/Instance/Models/_E2_Navigate.cs new file mode 100644 index 0000000..a6296b4 --- /dev/null +++ b/Instance/Models/_E2_Navigate.cs @@ -0,0 +1,230 @@ +using System.Text.Json; +using View_by_Distance.Instance.Models.Stateless; +using View_by_Distance.Metadata.Models; +using View_by_Distance.Resize.Models; +using View_by_Distance.Shared.Models; +using View_by_Distance.Shared.Models.Methods; + +namespace View_by_Distance.Instance.Models; + +/// +// N/A +/// +internal class E2_Navigate +{ + + private readonly string _ArgZero; + private readonly E3_Rename _Rename; + private readonly IConsole _Console; + private readonly Serilog.ILogger? _Log; + private readonly Configuration _Configuration; + + internal E2_Navigate(IConsole console, Configuration configuration, string argZero) + { + _Console = console; + _ArgZero = argZero; + _Configuration = configuration; + _Rename = new E3_Rename(configuration); + _Log = Serilog.Log.ForContext(); + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + + private void DisplayTags(Property.Models.Configuration configuration, string outputResolution, string[] directories, Dictionary directoryKeyValuePairs, string[] files, Dictionary fileKeyValuePairs) + { + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + bool all = false; + FileSystem fileSystem; + string requestPath = "/RootResultsDirectory"; + string? rootResultsDirectory = Path.GetDirectoryName(Property.Models.Stateless.IResult.GetResultsGroupDirectory(configuration, nameof(B_Metadata))); + if (string.IsNullOrEmpty(rootResultsDirectory)) + throw new Exception(); + string rootResultsDirectoryAbsoluteUri = new Uri(rootResultsDirectory).AbsoluteUri; + string dFacesContentDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, nameof(D_Face), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "()"); + string cResizeContentDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, nameof(C_Resize), outputResolution, includeResizeGroup: true, includeModel: false, includePredictorModel: false), "()"); + string eDistanceCollectionDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, nameof(E_Distance), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "[]"); + (string RootResultsDirectoryAbsoluteUri, string C_ResizeContentDirectory, string D_FacesContentDirectory, string E_DistanceCollectionDirectory) tuple = new(rootResultsDirectoryAbsoluteUri, cResizeContentDirectory, dFacesContentDirectory, eDistanceCollectionDirectory); + List fileSystemCollection = Shared.Models.Stateless.Methods.IFileSystem.GetFileSystemCollection(requestPath, tuple, directories, files, all); + Queue queue = new(fileSystemCollection); + foreach (KeyValuePair element in directoryKeyValuePairs) + { + fileSystem = queue.Dequeue(); + _Log.Warn(string.Concat(element.Key, " - D) ", " <", fileSystem.Display, ">")); + // _Log.Info(string.Join(Environment.NewLine, from l in fileSystem where !string.IsNullOrEmpty(l) select l)); + _Log.Info(string.Empty); + } + foreach (KeyValuePair element in fileKeyValuePairs) + { + fileSystem = queue.Dequeue(); + _Log.Warn(string.Concat(element.Key, " - F) [", fileSystem.Display, '}')); + // _Log.Info(string.Join(Environment.NewLine, from l in fileSystem where !string.IsNullOrEmpty(l) select l)); + _Log.Info(string.Empty); + } + } + + private void DisplayFaces(Property.Models.Configuration configuration, string outputResolution, string selectedFileFullName) + { + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + string requestPath = "/RootResultsDirectory"; + string? rootResultsDirectory = Path.GetDirectoryName(Property.Models.Stateless.IResult.GetResultsGroupDirectory(configuration, nameof(B_Metadata))); + if (string.IsNullOrEmpty(rootResultsDirectory)) + throw new Exception(); + string rootResultsDirectoryAbsoluteUri = new Uri(rootResultsDirectory).AbsoluteUri; + string dFacesContentDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, nameof(D_Face), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "()"); + string cResizeContentDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, nameof(C_Resize), outputResolution, includeResizeGroup: true, includeModel: false, includePredictorModel: false), "()"); + string eDistanceCollectionDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, nameof(E_Distance), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "[]"); + (string RootResultsDirectoryAbsoluteUri, string C_ResizeContentDirectory, string D_FacesContentDirectory, string E_DistanceCollectionDirectory) tuple = new(rootResultsDirectoryAbsoluteUri, cResizeContentDirectory, dFacesContentDirectory, eDistanceCollectionDirectory); + FaceFileSystem[] faceFileSystemCollection = Shared.Models.Stateless.Methods.IFaceFileSystem.GetFaceFileSystemCollection(requestPath, tuple, selectedFileFullName); + for (int i = 0; i < faceFileSystemCollection.Length; i++) + { + _Log.Warn(string.Concat(i, " - F) [", faceFileSystemCollection[i].Display, '}')); + // _Log.Info(string.Join(Environment.NewLine, from l in fileSystemCollection[i] where !string.IsNullOrEmpty(l) select l)); + _Log.Info(string.Empty); + } + // } + } + + private string Rename(Property.Models.Configuration configuration, string subSourceDirectory) + { + string result; + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + if (_Configuration?.PropertyConfiguration is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + _Log.Warn(string.Concat("What is the new name for [", Path.GetFileName(subSourceDirectory), "]<", subSourceDirectory, ">?")); + string? newDirectoryName = _Console.ReadLine(); + _Log.Warn("Are you sure y[es] || n[o]?"); + if (string.IsNullOrEmpty(newDirectoryName) || _Console.ReadKey() != ConsoleKey.Y) + { + _Log.Warn(string.Empty); + _Log.Warn("No changes made."); + result = subSourceDirectory; + } + else + { + _Log.Warn(string.Empty); + string eDistanceCollectionDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, nameof(E_Distance), _Configuration.ValidResolutions[0], includeResizeGroup: true, includeModel: true, includePredictorModel: true), "[]"); + string relativePath = Property.Models.Stateless.IPath.GetRelativePath(subSourceDirectory, eDistanceCollectionDirectory.Length); + if (relativePath.Length == 1) + throw new Exception(); + if (Directory.Exists(Path.Combine(string.Concat(_Configuration.PropertyConfiguration.RootDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName))) + { + _Log.Warn("\"To\" directory already exits!"); + result = subSourceDirectory; + } + else + { + _Rename.DirectoryRename(configuration, relativePath, newDirectoryName); + _Log.Warn("Renamed..."); + string? directoryName = Path.GetDirectoryName(subSourceDirectory); + if (string.IsNullOrEmpty(directoryName)) + throw new Exception(); + result = Path.Combine(directoryName, newDirectoryName); + } + } + return result; + } + + internal void Navigate(Property.Models.Configuration configuration, string outputResolution) + { + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + string[] subFiles; + ConsoleKey consoleKey; + string[] subDirectories; + string selectedFileFullName; + string rootDirectory = string.Empty; + string? subSourceDirectory = string.Empty; + Dictionary fileKeyValuePairs = new(); + Dictionary directoryKeyValuePairs = new(); + string eDistanceCollectionDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, nameof(E_Distance), _Configuration.OutputResolutions[0], includeResizeGroup: true, includeModel: true, includePredictorModel: true), "[]"); + if (!Directory.Exists(eDistanceCollectionDirectory)) + _ = Directory.CreateDirectory(eDistanceCollectionDirectory); + for (int z = 0; z < int.MaxValue; z++) + { + if (string.IsNullOrEmpty(subSourceDirectory)) + { + rootDirectory = eDistanceCollectionDirectory; + subSourceDirectory = rootDirectory; + } + subFiles = Directory.GetFiles(subSourceDirectory, "*.json", SearchOption.TopDirectoryOnly); + subDirectories = Directory.GetDirectories(subSourceDirectory, "*", SearchOption.TopDirectoryOnly); + directoryKeyValuePairs.Clear(); + for (int i = (int)ConsoleKey.A; i < (subDirectories.Length + (int)ConsoleKey.A) && i <= (int)ConsoleKey.RightWindows; i++) + directoryKeyValuePairs.Add((ConsoleKey)i, i - (int)ConsoleKey.A); + fileKeyValuePairs.Clear(); + for (int i = (int)ConsoleKey.A + subDirectories.Length; i < (subFiles.Length + (int)ConsoleKey.A + subDirectories.Length) && i <= (int)ConsoleKey.RightWindows; i++) + fileKeyValuePairs.Add((ConsoleKey)i, i - (int)ConsoleKey.A); + _Log.Warn(""); + DisplayTags(configuration, outputResolution, subDirectories, directoryKeyValuePairs, subFiles, fileKeyValuePairs); + _Log.Warn(string.Empty); + _Log.Warn(string.Empty); + _Log.Warn(string.Empty); + _Log.Warn("Select a file system object. Enter \"Backspace\" to go up a directory, \"F2\" to rename and \"Esc\" to end navigation."); + consoleKey = _Console.ReadKey(); + _Log.Warn(string.Empty); + if (consoleKey == ConsoleKey.Escape) + break; + if (consoleKey == ConsoleKey.F2) + { + if (subSourceDirectory == rootDirectory) + { + _Log.Warn("Root directory can not be renamed! Try again."); + continue; + } + else + { + subSourceDirectory = Rename(configuration, subSourceDirectory); + continue; + } + } + else if (consoleKey is ConsoleKey.Backspace or ConsoleKey.LeftArrow) + { + if (subSourceDirectory != rootDirectory) + subSourceDirectory = Path.GetDirectoryName(subSourceDirectory); + else + { + _Log.Warn("At root directory. Try again."); + continue; + } + } + else if (directoryKeyValuePairs.ContainsKey(consoleKey)) + { + subSourceDirectory = subDirectories[directoryKeyValuePairs[consoleKey]]; + _Log.Warn(string.Concat(">>> [", Path.GetFileName(subSourceDirectory), "]<", subSourceDirectory, ">?")); + continue; + } + else + { + if (!fileKeyValuePairs.ContainsKey(consoleKey)) + { + subSourceDirectory = _ArgZero; + _Log.Warn("Invalid selection. Try again."); + continue; + } + else + { + selectedFileFullName = subFiles[fileKeyValuePairs[consoleKey]]; + _Log.Warn(string.Concat(">>> [", Path.GetFileName(selectedFileFullName), "]<", selectedFileFullName, ">?")); + DisplayFaces(configuration, outputResolution, selectedFileFullName); + _Log.Warn(string.Empty); + _Log.Warn(string.Empty); + _Log.Warn(string.Empty); + _Log.Warn("Go up a directory? Enter escape end."); + consoleKey = _Console.ReadKey(); + if (consoleKey == ConsoleKey.Escape) + break; + subSourceDirectory = Path.GetDirectoryName(subSourceDirectory); + continue; + } + } + } + } + +} \ No newline at end of file diff --git a/Instance/Models/_E3_Rename.cs b/Instance/Models/_E3_Rename.cs new file mode 100644 index 0000000..1d318bd --- /dev/null +++ b/Instance/Models/_E3_Rename.cs @@ -0,0 +1,338 @@ +using System.Text.Json; +using View_by_Distance.Metadata.Models; +using View_by_Distance.Property.Models; +using View_by_Distance.Resize.Models; + +namespace View_by_Distance.Instance.Models; + +/// +// N/A +/// +internal class E3_Rename +{ + + private readonly Serilog.ILogger? _Log; + private readonly Configuration _Configuration; + private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions; + + internal E3_Rename(Configuration configuration) + { + _Configuration = configuration; + _Log = Serilog.Log.ForContext(); + _WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true }; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + + internal string[] GetDirectoryRenameCollection(Property.Models.Configuration configuration, string relativePath, string newDirectoryName, bool jsonFiles4InfoAny) + { + List results = new(); + bool add; + string to; + string dFacesContentDirectory; + string cResizeContentDirectory; + string dFacesCollectionDirectory; + string cResizeSingletonDirectory; + string eDistanceContentDirectory; + string aPropertySingletonDirectory; + string bMetadataSingletonDirectory; + string eDistanceCollectionDirectory; + string g2IdentifyCollectionDirectory; + string d2FaceLandmarksContentDirectory; + add = Directory.Exists(string.Concat(Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, nameof(C_Resize), _Configuration.ValidResolutions[0], includeResizeGroup: true, includeModel: false, includePredictorModel: false), "()"), relativePath)); + bMetadataSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(B_Metadata), "{}"); + if (Directory.Exists(bMetadataSingletonDirectory)) + { + to = Path.Combine(string.Concat(bMetadataSingletonDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName); + results.Add(to); + } + aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "{}"); + if (Directory.Exists(aPropertySingletonDirectory)) + { + to = Path.Combine(string.Concat(aPropertySingletonDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName); + results.Add(to); + } + cResizeContentDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, nameof(C_Resize), _Configuration.ValidResolutions[0], includeResizeGroup: true, includeModel: false, includePredictorModel: false), "()"); + if (Directory.Exists(cResizeContentDirectory)) + { + to = Path.Combine(string.Concat(cResizeContentDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName); + results.Add(to); + } + foreach (string outputResolution in _Configuration.ValidResolutions) + { + cResizeSingletonDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, nameof(C_Resize), outputResolution, includeResizeGroup: true, includeModel: false, includePredictorModel: false), "{}"); + if (Directory.Exists(cResizeSingletonDirectory)) + { + to = Path.Combine(string.Concat(cResizeSingletonDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName); + results.Add(to); + } + dFacesContentDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, nameof(D_Face), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "()"); + if (Directory.Exists(dFacesContentDirectory)) + { + to = Path.Combine(string.Concat(dFacesContentDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName); + results.Add(to); + } + dFacesCollectionDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, nameof(D_Face), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "[]"); + if (Directory.Exists(dFacesCollectionDirectory)) + { + to = Path.Combine(string.Concat(dFacesCollectionDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName); + results.Add(to); + } + d2FaceLandmarksContentDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, nameof(D2_FaceLandmarks), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "()"); + if (add && _Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution) && Directory.Exists(d2FaceLandmarksContentDirectory)) + { + to = Path.Combine(string.Concat(d2FaceLandmarksContentDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName); + results.Add(to); + } + eDistanceContentDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, nameof(E_Distance), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "()"); + if (Directory.Exists(eDistanceContentDirectory)) + { + to = Path.Combine(string.Concat(eDistanceContentDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName); + results.Add(to); + } + eDistanceCollectionDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, nameof(E_Distance), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "[]"); + if (Directory.Exists(eDistanceCollectionDirectory)) + { + to = Path.Combine(string.Concat(eDistanceCollectionDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName); + results.Add(to); + } + g2IdentifyCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(G2_Identify), "[]"); + if (add && jsonFiles4InfoAny && Directory.Exists(g2IdentifyCollectionDirectory)) + { + to = Path.Combine(string.Concat(g2IdentifyCollectionDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName); + results.Add(to); + } + } + return results.ToArray(); + } + + internal List GetDirectoryRenameCollections(Property.Models.Configuration configuration, string relativePath, string newDirectoryName, bool jsonFiles4InfoAny) + { + List results = new(); + if (_Configuration?.PropertyConfiguration is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + bool add; + string to; + bool exists; + string from; + string dFacesContentDirectory; + string cResizeContentDirectory; + string dFacesCollectionDirectory; + string cResizeSingletonDirectory; + string eDistanceContentDirectory; + string bMetadataSingletonDirectory; + string aPropertySingletonDirectory; + string eDistanceCollectionDirectory; + string g2IdentifyCollectionDirectory; + string d2FaceLandmarksContentDirectory; + if (!string.IsNullOrEmpty(relativePath)) + { + from = string.Concat(_Configuration.PropertyConfiguration.RootDirectory, relativePath); + to = Path.Combine(string.Concat(_Configuration.PropertyConfiguration.RootDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName); + results.Add(new string[] { from, to }); + } + foreach (string outputResolution in _Configuration.ValidResolutions) + { + add = Directory.Exists(string.Concat(Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, nameof(C_Resize), outputResolution, includeResizeGroup: true, includeModel: false, includePredictorModel: false), "()"), relativePath)); + bMetadataSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(B_Metadata), "{}"); + from = string.Concat(bMetadataSingletonDirectory, relativePath); + exists = Directory.Exists(bMetadataSingletonDirectory); + if (exists) + { + to = Path.Combine(string.Concat(bMetadataSingletonDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName); + results.Add(new string[] { from, to }); + } + aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "{}"); + from = string.Concat(aPropertySingletonDirectory, relativePath); + exists = Directory.Exists(aPropertySingletonDirectory); + if (exists) + { + to = Path.Combine(string.Concat(aPropertySingletonDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName); + results.Add(new string[] { from, to }); + } + cResizeContentDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, nameof(C_Resize), outputResolution, includeResizeGroup: true, includeModel: false, includePredictorModel: false), "()"); + from = string.Concat(cResizeContentDirectory, relativePath); + exists = Directory.Exists(cResizeContentDirectory); + if (exists) + { + to = Path.Combine(string.Concat(cResizeContentDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName); + results.Add(new string[] { from, to }); + } + cResizeSingletonDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, nameof(C_Resize), outputResolution, includeResizeGroup: true, includeModel: false, includePredictorModel: false), "{}"); + from = string.Concat(cResizeSingletonDirectory, relativePath); + exists = Directory.Exists(cResizeSingletonDirectory); + if (exists) + { + to = Path.Combine(string.Concat(cResizeSingletonDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName); + results.Add(new string[] { from, to }); + } + dFacesContentDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, nameof(D_Face), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "()"); + from = string.Concat(dFacesContentDirectory, relativePath); + exists = Directory.Exists(dFacesContentDirectory); + if (exists) + { + to = Path.Combine(string.Concat(dFacesContentDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName); + results.Add(new string[] { from, to }); + } + dFacesCollectionDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, nameof(D_Face), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "[]"); + from = string.Concat(dFacesCollectionDirectory, relativePath); + exists = Directory.Exists(dFacesCollectionDirectory); + if (exists) + { + to = Path.Combine(string.Concat(dFacesCollectionDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName); + results.Add(new string[] { from, to }); + } + d2FaceLandmarksContentDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, nameof(D2_FaceLandmarks), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "()"); + from = string.Concat(d2FaceLandmarksContentDirectory, relativePath); + exists = Directory.Exists(d2FaceLandmarksContentDirectory); + if (!exists && add && _Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution)) + results.Add(new string[] { from }); + else if (exists) + { + to = Path.Combine(string.Concat(d2FaceLandmarksContentDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName); + results.Add(new string[] { from, to }); + } + eDistanceContentDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, nameof(E_Distance), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "()"); + from = string.Concat(eDistanceContentDirectory, relativePath); + exists = Directory.Exists(eDistanceContentDirectory); + if (exists) + { + to = Path.Combine(string.Concat(eDistanceContentDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName); + results.Add(new string[] { from, to }); + } + eDistanceCollectionDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, nameof(E_Distance), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "[]"); + from = string.Concat(eDistanceCollectionDirectory, relativePath); + exists = Directory.Exists(eDistanceCollectionDirectory); + if (exists) + { + to = Path.Combine(string.Concat(eDistanceCollectionDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName); + results.Add(new string[] { from, to }); + } + g2IdentifyCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(G2_Identify), "[]"); + from = string.Concat(g2IdentifyCollectionDirectory, relativePath); + exists = Directory.Exists(g2IdentifyCollectionDirectory); + if (!exists && add && jsonFiles4InfoAny) + results.Add(new string[] { from }); + else if (exists) + { + to = Path.Combine(string.Concat(g2IdentifyCollectionDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName); + results.Add(new string[] { from, to }); + } + } + return results; + } + + internal void DirectoryRename(Property.Models.Configuration configuration, string relativePath, string newDirectoryName) + { + if (_Configuration?.PropertyConfiguration is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + string json; + FileInfo current; + FileInfo fileInfo; + string error = "Error"; + string target = "Target"; + string pending = "Pending"; + DirectoryInfo directoryInfo; + IEnumerator fileInfoCollection; + string oldValue = string.Concat("\"", relativePath); + string oldDirectoryName = Path.GetFileName(relativePath); + string traceFileName = string.Concat(DateTime.Now.Ticks, ".tsv"); + string directoryName = Path.GetFileName(_Configuration.PropertyConfiguration.RootDirectory); + string? relativePathParent = Path.GetDirectoryName(relativePath); + if (string.IsNullOrEmpty(relativePathParent)) + throw new Exception(); + string newValue = string.Concat("\"", Path.Combine(relativePathParent, newDirectoryName)); + string e3RenameContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(E3_Rename), "()"); + string jsonRootDirectory = Path.Combine(string.Concat(_Configuration.PropertyConfiguration.RootDirectory, " - Copied"), string.Concat(directoryName, " - 4) Info"), _Configuration.PropertyConfiguration.DateGroup, "[]"); + directoryInfo = new DirectoryInfo(jsonRootDirectory); + if (!directoryInfo.Exists) + directoryInfo.Create(); + IEnumerator fileInfoCollection4 = directoryInfo.EnumerateFiles("*.json", SearchOption.AllDirectories).GetEnumerator(); + bool fileInfoCollection4MoveNext = fileInfoCollection4.MoveNext(); + if (!fileInfoCollection4MoveNext) + current = new(string.Empty); + else + current = fileInfoCollection4.Current; + List directoryCollections = GetDirectoryRenameCollections(configuration, relativePath, newDirectoryName, fileInfoCollection4MoveNext); + if ((from l in directoryCollections where l.Length != 2 select true).Any()) + throw new Exception(); + if (!Directory.Exists(e3RenameContentDirectory)) + { + _ = Directory.CreateDirectory(e3RenameContentDirectory); + _ = Directory.CreateDirectory(Path.Combine(e3RenameContentDirectory, error)); + _ = Directory.CreateDirectory(Path.Combine(e3RenameContentDirectory, target)); + _ = Directory.CreateDirectory(Path.Combine(e3RenameContentDirectory, "Test")); + _ = Directory.CreateDirectory(Path.Combine(e3RenameContentDirectory, pending)); + } + string fRandomSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(F_Random), "{}"); + string[] files = Directory.GetFiles(fRandomSingletonDirectory, "*", SearchOption.TopDirectoryOnly); + foreach (string file in files) + File.Delete(file); + File.WriteAllText(Path.Combine(e3RenameContentDirectory, pending, traceFileName), string.Concat(relativePath, newDirectoryName, Environment.NewLine)); + try + { + foreach (string[] directoryCollection in directoryCollections) + { + directoryInfo = new DirectoryInfo(directoryCollection[0]); + if (!directoryInfo.Exists) + continue; + fileInfoCollection = directoryInfo.EnumerateFiles("*.json", SearchOption.AllDirectories).GetEnumerator(); + for (int i = 0; i < int.MaxValue; i++) + { + if (fileInfoCollection.MoveNext()) + fileInfo = fileInfoCollection.Current; + else if (fileInfoCollection4MoveNext && fileInfoCollection4.MoveNext()) + fileInfo = fileInfoCollection4.Current; + else if (fileInfoCollection4MoveNext && current is not null) + { + fileInfo = current; + current = new(string.Empty); + } + else + break; + json = Shared.Models.Stateless.Methods.IIndex.GetJson(fileInfo.FullName, fileInfo); + if (json.Contains(oldValue)) + { + json = json.Replace(oldValue, newValue); + if (!Property.Models.Stateless.IPath.WriteAllText(fileInfo.FullName, json, compareBeforeWrite: true)) + continue; + File.SetLastWriteTime(fileInfo.FullName, fileInfo.LastWriteTime); + } + } + Directory.Move(directoryCollection[0], directoryCollection[1]); + } + File.Move(Path.Combine(e3RenameContentDirectory, pending, traceFileName), Path.Combine(e3RenameContentDirectory, target, traceFileName)); + } + catch (Exception) + { + File.Move(Path.Combine(e3RenameContentDirectory, pending, traceFileName), Path.Combine(e3RenameContentDirectory, error, traceFileName)); + throw; + } + } + + internal void RenameQueue(Property.Models.Configuration configuration) + { + string[] lines; + string[] segments; + string e3RenameContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(E3_Rename), "()"); + string[] files = Directory.GetFiles(e3RenameContentDirectory, "*.tsv", SearchOption.TopDirectoryOnly); + foreach (string file in files) + { + lines = File.ReadAllLines(file); + foreach (string line in lines) + { + if (string.IsNullOrEmpty(line) || !line.Contains('\t')) + continue; + segments = line.Split('\t'); + if (segments.Length != 2) + throw new Exception(); + DirectoryRename(configuration, segments[0], segments[1]); + } + } + } + +} \ No newline at end of file diff --git a/Instance/Models/_E_Distance.cs b/Instance/Models/_E_Distance.cs new file mode 100644 index 0000000..5f91577 --- /dev/null +++ b/Instance/Models/_E_Distance.cs @@ -0,0 +1,390 @@ +using FaceRecognitionDotNet; +using System.Text; +using System.Text.Json; +using View_by_Distance.Metadata.Models; +using View_by_Distance.Property.Models; +using View_by_Distance.Resize.Models; + +namespace View_by_Distance.Instance.Models; + +/// +// List +/// + +internal class E_Distance +{ + + private readonly Serilog.ILogger? _Log; + private readonly Configuration _Configuration; + private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions; + + internal E_Distance(Configuration configuration) + { + _Configuration = configuration; + _Log = Serilog.Log.ForContext(); + _WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true }; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + + private static void LoadFaceEncodingCollections(string[] subFiles, List> faceCollections, List locationIndicesCollection, List faceEncodingCollection, List> faceEncodingCollections) + { + List faceCollection; + FaceEncoding faceEncoding; + for (int i = 0; i < subFiles.Length; i++) + { + faceCollection = faceCollections[i]; + if (!faceCollection.Any()) + throw new Exception(); + faceEncodingCollections.Add(new List()); + for (int j = 0; j < faceCollection.Count; j++) + { + if (!faceCollection[j].Populated) + continue; + faceEncoding = FaceRecognition.LoadFaceEncoding(faceCollection[j].FaceEncoding.RawEncoding); + faceEncodingCollection.Add(faceEncoding); + faceEncodingCollections[i].Add(faceEncoding); + locationIndicesCollection.Add(new int[] { i, j }); + } + } + } + + private List> GetOrderedNoFaceCollection(List> faceCollections, int i, D_Face face) + { + List> results = new() { new(face, string.Empty) }; + if (_Configuration.MaxItemsInDistanceCollection is null) + throw new Exception(); + for (int n = 0; n < faceCollections.Count; n++) + { + if (i == n) + continue; + for (int j = 0; j < faceCollections[n].Count; j++) + results.Add(new(faceCollections[n][j], string.Empty)); + } + for (int r = results.Count - 1; r > _Configuration.MaxItemsInDistanceCollection.Value; r--) + results.RemoveAt(r); + return results; + } + + private List GetValues(List> faceCollections, List locationIndicesCollection, double[] faceDistances) + { + List results = new(); + if (_Configuration.LocationConfidenceFactor is null) + throw new Exception(); + if (_Configuration.DistanceFactor is null) + throw new Exception(); + D_Face face; + int[] locationIndices; + for (int d = 0; d < faceDistances.Length; d++) + { + locationIndices = locationIndicesCollection[d]; + face = faceCollections[locationIndices[0]][locationIndices[1]]; + if (face.Populated && face.LocationIndex is not null && locationIndices[1] != face.LocationIndex) + throw new Exception(); + results.Add(new double[] { d, faceDistances[d], (faceDistances[d] * _Configuration.DistanceFactor.Value) + face.Location.Confidence * _Configuration.LocationConfidenceFactor.Value / 10 }); + } + results = (from l in results orderby l[2] select l).ToList(); + return results; + } + + private List> GetOrderedFaceCollection(List> faceCollections, List locationIndicesCollection, List indicesAndValues) + { + List> results = new(); + if (_Configuration.MaxItemsInDistanceCollection is null) + throw new Exception(); + int[] locationIndices; + for (int t = 0; t < indicesAndValues.Count; t++) + { + locationIndices = locationIndicesCollection[(int)indicesAndValues[t][0]]; + results.Add(new(faceCollections[locationIndices[0]][locationIndices[1]], string.Join('|', (from l in indicesAndValues[t] select l.ToString("0.000")).ToArray(), 1, indicesAndValues[t].Length - 1))); + } + for (int r = results.Count - 1; r > _Configuration.MaxItemsInDistanceCollection.Value; r--) + results.RemoveAt(r); + return results; + } + + private static string GetText(string fileNameWithoutExtension, List> faceCollections, List locationIndicesCollection, List indicesAndValues) + { + string result; + D_Face face; + int[] locationIndices; + StringBuilder tvs = new(); + _ = tvs.Append("FileNameWithoutExtension").Append('\t').Append("LocationIndex").Append('\t').Append("FaceConfidence").Append('\t').Append("FaceDistance").Append('\t').Append("FactoredValue").AppendLine(); + for (int t = 0; t < indicesAndValues.Count; t++) + { + locationIndices = locationIndicesCollection[(int)indicesAndValues[t][0]]; + face = faceCollections[locationIndices[0]][locationIndices[1]]; + if (face.Populated && face.LocationIndex is not null && locationIndices[1] != face.LocationIndex) + throw new Exception(); + _ = tvs.Append(fileNameWithoutExtension).Append('\t').Append(face.LocationIndex).Append('\t').Append(face.Location.Confidence).Append('\t').Append(indicesAndValues[t][1]).Append('\t').Append(indicesAndValues[t][2]).AppendLine(); + } + result = tvs.ToString(); + return result; + } + + private void LoadOrCreateThenSaveDistanceResultsLoop(Property.Models.Configuration configuration, List> faceCollections, int subFilesCount, int i, List faceCollection, List locationIndicesCollection, List> subFileTuples, List faceEncodingCollection, List faceEncodingCollections, string fileNameWithoutExtension, string jsonDirectory, string tvsDirectory) + { + string text; + string json; + string jsonFile; + List> orderedFaceCollection; + if (!Directory.Exists(jsonDirectory)) + _ = Directory.CreateDirectory(jsonDirectory); + if (!Directory.Exists(tvsDirectory)) + _ = Directory.CreateDirectory(tvsDirectory); + if (!faceEncodingCollections.Any()) + { + int j = 0; + orderedFaceCollection = GetOrderedNoFaceCollection(faceCollections, i, faceCollection[j]); + json = JsonSerializer.Serialize(orderedFaceCollection, _WriteIndentedJsonSerializerOptions); + jsonFile = Path.Combine(jsonDirectory, $"{j} - {fileNameWithoutExtension}.json"); + if (Property.Models.Stateless.IPath.WriteAllText(jsonFile, json, compareBeforeWrite: true)) + subFileTuples.Add(new Tuple(nameof(E_Distance), DateTime.Now)); + } + else + { + string tvsFile; + double[] faceDistances; + List indicesAndValues; + for (int j = 0; j < faceEncodingCollections.Count; j++) + { + if (!faceCollection[j].Populated) + continue; + tvsFile = Path.Combine(tvsDirectory, $"{j} - {fileNameWithoutExtension}.tvs"); + jsonFile = Path.Combine(jsonDirectory, $"{j} - {fileNameWithoutExtension}.json"); + faceDistances = FaceRecognition.FaceDistances(faceEncodingCollection, faceEncodingCollections[j]).ToArray(); + indicesAndValues = GetValues(faceCollections, locationIndicesCollection, faceDistances); + orderedFaceCollection = GetOrderedFaceCollection(faceCollections, locationIndicesCollection, indicesAndValues); + text = GetText(fileNameWithoutExtension, faceCollections, locationIndicesCollection, indicesAndValues); + if (Property.Models.Stateless.IPath.WriteAllText(tvsFile, text, compareBeforeWrite: true)) + subFileTuples.Add(new Tuple(nameof(E_Distance), DateTime.Now)); + json = JsonSerializer.Serialize(orderedFaceCollection, _WriteIndentedJsonSerializerOptions); + if (Property.Models.Stateless.IPath.WriteAllText(jsonFile, json, compareBeforeWrite: true)) + subFileTuples.Add(new Tuple(nameof(E_Distance), DateTime.Now)); + } + } + } + + private void LoadOrCreateThenSaveDistanceResults(Property.Models.Configuration configuration, string[] subFiles, List> faceCollections, List directories) + { + string fileNameWithoutExtension; + List locationIndicesCollection = new(); + List> subFileTuples = new(); + List faceEncodingCollection = new(); + List> faceEncodingCollections = new(); + LoadFaceEncodingCollections(subFiles, faceCollections, locationIndicesCollection, faceEncodingCollection, faceEncodingCollections); + if (faceEncodingCollections.Count != faceCollections.Count) + throw new Exception(); + if (locationIndicesCollection.Count != faceEncodingCollection.Count) + throw new Exception(); + for (int i = 0; i < subFiles.Length; i++) + { + fileNameWithoutExtension = Path.GetFileNameWithoutExtension(subFiles[i]); + LoadOrCreateThenSaveDistanceResultsLoop(configuration, faceCollections, subFiles.Length, i, faceCollections[i], locationIndicesCollection, subFileTuples, faceEncodingCollection, faceEncodingCollections[i], fileNameWithoutExtension, directories[i][0], directories[i][1]); + } + } + + internal void LoadOrCreateThenSaveDistanceResults(Property.Models.Configuration configuration, string sourceDirectory, string outputResolution, List> sourceDirectoryChanges, string[] subFiles, List> faceCollections) + { + if (_Configuration.CheckJsonForDistanceResults is null) + throw new Exception(); + if (_Configuration.PropertiesChangedForDistance is null) + throw new Exception(); + string json; + bool check = false; + string parentCheck; + DirectoryInfo directoryInfo; + DirectoryInfo tvsDirectoryInfo; + string fileNameWithoutExtension; + List directories = new(); + string[] changesFrom = new string[] { nameof(A_Property), nameof(B_Metadata), nameof(C_Resize), nameof(D_Face) }; + List dateTimes = (from l in sourceDirectoryChanges where changesFrom.Contains(l.Item1) select l.Item2).ToList(); + List directoryInfoCollection = Property.Models.Stateless.IResult.GetDirectoryInfoCollection(configuration, + sourceDirectory, + nameof(E_Distance), + outputResolution, + includeResizeGroup: true, + includeModel: true, + includePredictorModel: true, + contentDescription: ".tvs File", + singletonDescription: string.Empty, + collectionDescription: "n json file(s) for each face found (one to many)"); + for (int i = 0; i < subFiles.Length; i++) + { + fileNameWithoutExtension = Path.GetFileNameWithoutExtension(subFiles[i]); + directoryInfo = new DirectoryInfo(Path.Combine(directoryInfoCollection[0].Replace("<>", "[]"), fileNameWithoutExtension)); + if (!directoryInfo.Exists) + { + if (directoryInfo.Parent?.Parent is null) + throw new Exception(); + parentCheck = Path.Combine(directoryInfo.Parent.Parent.FullName, directoryInfo.Name); + if (Directory.Exists(parentCheck)) + { + foreach (string file in Directory.GetFiles(parentCheck)) + File.Delete(file); + Directory.Delete(parentCheck); + } + } + tvsDirectoryInfo = new DirectoryInfo(Path.Combine(directoryInfoCollection[0].Replace("<>", "()"), fileNameWithoutExtension)); + directories.Add(new string[] { directoryInfo.FullName, tvsDirectoryInfo.FullName }); + if (_Configuration.CheckJsonForDistanceResults.Value && directoryInfo.Exists) + { + foreach (FileInfo fileInfo in directoryInfo.GetFiles("*.json", SearchOption.AllDirectories)) + { + json = Shared.Models.Stateless.Methods.IIndex.GetJson(fileInfo.FullName, fileInfo); + if (!_Configuration.PropertiesChangedForDistance.Value && Shared.Models.Stateless.Methods.IFace.GetFace(fileInfo.FullName) is null) + check = true; + } + } + if (check) + continue; + if (_Configuration.PropertiesChangedForDistance.Value) + check = true; + else if (!directoryInfo.Exists) + check = true; + else if (!tvsDirectoryInfo.Exists) + check = true; + else if (dateTimes.Any() && dateTimes.Max() > directoryInfo.LastWriteTime) + check = true; + } + if (check) + LoadOrCreateThenSaveDistanceResults(configuration, subFiles, faceCollections, directories); + _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(directoryInfoCollection[0].Replace("<>", "()")); + } + + private List<(string, List>)> GetFiles(Property.Models.Configuration configuration, string outputResolution) + { + string json; + List>? facesKeyValuePairCollection; + List<(string, List>)> results = new(); + string dFacesCollectionDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, nameof(D_Face), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "[[]]"); + string[] dFacesCollectionFiles = Directory.GetFiles(dFacesCollectionDirectory, "*.json", SearchOption.TopDirectoryOnly); + foreach (string dFacesCollectionFile in dFacesCollectionFiles) + { + json = File.ReadAllText(dFacesCollectionFile); + facesKeyValuePairCollection = JsonSerializer.Deserialize>>(json); + if (facesKeyValuePairCollection is null) + continue; + results.Add(new(dFacesCollectionFile, facesKeyValuePairCollection)); + } + return results; + } + + private static List<(string, List, List)> GetMatches(List<(string, List>)> files) + { + List<(string, List, List)> results = new(); + List faces; + FaceEncoding faceEncoding; + List faceEncodings; + foreach ((string, List>) file in files) + { + faces = new(); + faceEncodings = new(); + foreach (KeyValuePair keyValuePair in file.Item2) + { + foreach (Shared.Models.Face face in keyValuePair.Value) + { + if (!face.Populated) + continue; + faces.Add(face); + faceEncoding = FaceRecognition.LoadFaceEncoding(face.FaceEncoding.RawEncoding); + faceEncodings.Add(faceEncoding); + } + } + results.Add(new(file.Item1, faces, faceEncodings)); + } + return results; + } + + private static int GetIndex(double[] faceDistances) + { + int result; + List faceDistancesWithIndex = new(); + for (int y = 0; y < faceDistances.Length; y++) + faceDistancesWithIndex.Add(new double[] { faceDistances[y], y }); + faceDistancesWithIndex = (from l in faceDistancesWithIndex orderby l[0] select l).ToList(); + result = (int)faceDistancesWithIndex[0][1]; + return result; + } + + private void Save(Property.Models.Configuration configuration, string outputResolution, string eDistanceCollectionDirectory, int k, string relativePath, Shared.Models.Face face, List> faceAndFaceDistanceCollection) + { + if (string.IsNullOrEmpty(eDistanceCollectionDirectory)) + eDistanceCollectionDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, nameof(E_Distance), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "[]"); + string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(face.RelativePath); + string jsonDirectory = string.Concat(eDistanceCollectionDirectory, Path.Combine(relativePath, fileNameWithoutExtension)); + if (!Directory.Exists(jsonDirectory)) + _ = Directory.CreateDirectory(jsonDirectory); + string json = JsonSerializer.Serialize(faceAndFaceDistanceCollection, _WriteIndentedJsonSerializerOptions); + string jsonFile = Path.Combine(jsonDirectory, $"{k} - {fileNameWithoutExtension}.nosj"); + _ = Property.Models.Stateless.IPath.WriteAllText(jsonFile, json, compareBeforeWrite: true); + } + + private static Tuple Get(FaceEncoding faceEncoding, (string, List, List) match) + { + Tuple result; + double[] faceDistances = FaceRecognition.FaceDistances(match.Item3, faceEncoding).ToArray(); + int index = GetIndex(faceDistances); + result = new(match.Item2[index], faceDistances[index]); + return result; + } + + internal void LoadOrCreateThenSaveDirectoryDistanceResults(Property.Models.Configuration configuration, string outputResolution) + { + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + string? relativePath; + Shared.Models.Face face; + ParallelOptions parallelOptions = new(); + FaceEncoding faceEncoding; + string eDistanceCollectionDirectory = string.Empty; + Tuple faceAndFaceDistance; + List> faceAndFaceDistanceCollection; + List<(string, List>)> files = GetFiles(configuration, outputResolution); + List<(string, List, List)> matches = GetMatches(files); + if (files.Count != matches.Count) + throw new Exception(); + int filesCount = files.Count; + for (int i = 0; i < filesCount; i++) + { + if (_Configuration.CrossDirectoryMaxItemsInDistanceCollection is null) + continue; + _Log.Debug(string.Concat("LoadOrCreateThenSaveDirectoryDistanceResults - ", nameof(outputResolution), ' ', outputResolution, " - ", i, " of ", filesCount)); + for (int j = 0; j < files[i].Item2.Count; j++) + { + if (!matches[i].Item2.Any()) + continue; + for (int k = 0; k < files[i].Item2[j].Value.Length; k++) + { + if (!files[i].Item2[j].Value[k].Populated) + continue; + face = files[i].Item2[j].Value[k]; + faceAndFaceDistanceCollection = new(matches.Count); + relativePath = Path.GetDirectoryName(face.RelativePath); + if (string.IsNullOrEmpty(relativePath)) + continue; + faceEncoding = FaceRecognition.LoadFaceEncoding(face.FaceEncoding.RawEncoding); + _ = Parallel.For(0, matches.Count, parallelOptions, z => + { + if (z != i && matches[z].Item2.Any()) + { + faceAndFaceDistance = Get(faceEncoding, matches[z]); + // if (faceAndFaceDistance.Item2 < _Configuration.) + faceAndFaceDistanceCollection.Add(new(faceAndFaceDistance.Item1, faceAndFaceDistance.Item2.ToString("0.000"))); + } + }); + if (faceAndFaceDistanceCollection.Any()) + { + faceAndFaceDistanceCollection = (from l in faceAndFaceDistanceCollection orderby l.Item2 select l).Take(_Configuration.CrossDirectoryMaxItemsInDistanceCollection.Value).ToList(); + Save(configuration, outputResolution, eDistanceCollectionDirectory, k, relativePath, face, faceAndFaceDistanceCollection); + } + } + } + } + } + +} \ No newline at end of file diff --git a/Instance/Models/_F_Random.cs b/Instance/Models/_F_Random.cs new file mode 100644 index 0000000..c9c980b --- /dev/null +++ b/Instance/Models/_F_Random.cs @@ -0,0 +1,90 @@ +using System.Text.Json; + +namespace View_by_Distance.Instance.Models; + +/// +// List +/// +internal class F_Random +{ + + private readonly Serilog.ILogger? _Log; + private readonly Configuration _Configuration; + private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions; + + internal F_Random(Configuration configuration) + { + _Configuration = configuration; + _Log = Serilog.Log.ForContext(); + _WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = false }; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + + private bool IsIgnoreRelativePath(string directory) + { + bool result = false; + if (_Configuration?.PropertyConfiguration is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + string? checkDirectory = Path.GetFullPath(directory); + for (int i = 0; i < int.MaxValue; i++) + { + if (_Configuration.IgnoreRelativePaths.Contains(Path.GetFileName(checkDirectory))) + { + result = true; + break; + } + checkDirectory = Path.GetDirectoryName(checkDirectory); + if (string.IsNullOrEmpty(checkDirectory) || checkDirectory == _Configuration.PropertyConfiguration.RootDirectory) + break; + } + return result; + } + + internal void Random(Property.Models.Configuration configuration, string outputResolution, List> fileKeyValuePairs) + { + if (_Configuration.SaveFullYearOfRandomFiles is null) + throw new Exception(); + string json; + string jsonFile; + Random random = new(); + List relativePaths = new(); + List ignoreRelativePaths = new(); + DateTime dateTime = new(2024, 1, 1); //Leap year + string fRandomCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(F_Random), "[]"); + string[] files = Directory.GetFiles(fRandomCollectionDirectory, "*", SearchOption.TopDirectoryOnly); + foreach (string file in files) + File.Delete(file); + foreach (KeyValuePair keyValuePair in fileKeyValuePairs) + { + if (!(from l in _Configuration.IgnoreRelativePaths where keyValuePair.Key.Contains(l) && IsIgnoreRelativePath(keyValuePair.Key) select true).Any()) + relativePaths.Add(keyValuePair.Value); + else + ignoreRelativePaths.Add(keyValuePair.Value); + } + if (relativePaths.Any()) + { + for (int i = 0; i < 366; i++) + { + relativePaths = (from l in relativePaths orderby random.NextDouble() select l).ToList(); + jsonFile = Path.Combine(fRandomCollectionDirectory, $"{dateTime.AddDays(i):MM-dd}.json"); + json = JsonSerializer.Serialize(relativePaths, _WriteIndentedJsonSerializerOptions); + _ = Property.Models.Stateless.IPath.WriteAllText(jsonFile, json, compareBeforeWrite: false); + if (!_Configuration.SaveFullYearOfRandomFiles.Value) + break; + } + } + if (ignoreRelativePaths.Any()) + { + ignoreRelativePaths = (from l in ignoreRelativePaths orderby random.NextDouble() select l).ToList(); + jsonFile = Path.Combine(fRandomCollectionDirectory, "01-01.txt"); + json = JsonSerializer.Serialize(ignoreRelativePaths, _WriteIndentedJsonSerializerOptions); + _ = Property.Models.Stateless.IPath.WriteAllText(jsonFile, json, compareBeforeWrite: false); + } + } + +} \ No newline at end of file diff --git a/Instance/Models/_G2_Identify.cs b/Instance/Models/_G2_Identify.cs new file mode 100644 index 0000000..cd138cc --- /dev/null +++ b/Instance/Models/_G2_Identify.cs @@ -0,0 +1,229 @@ +using Phares.Shared; +using System.Text.Json; +using System.Text.Json.Serialization; +using View_by_Distance.Property.Models; +using View_by_Distance.Shared.Models; +using View_by_Distance.Shared.Models.Methods; + +namespace View_by_Distance.Instance.Models; + +/// +// List +/// +public class G2_Identify : Shared.Models.Properties.IIdentify, IIdentify +{ + + protected int _DirectoryCount; + protected string _ParentDirectoryName; + protected string _Person; + protected string _PossibleYear; + protected string _RelativePath; + public int DirectoryCount => _DirectoryCount; + public string ParentDirectoryName => _ParentDirectoryName; + public string Person => _Person; + public string PossibleYear => _PossibleYear; + public string RelativePath => _RelativePath; + + private readonly Serilog.ILogger? _Log; + private readonly Configuration _Configuration; + private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions; + +#nullable disable + [JsonConstructor] + public G2_Identify(int directoryCount, string parentDirectoryName, string person, string possibleYear, string relativePath) + { + _DirectoryCount = directoryCount; + _ParentDirectoryName = parentDirectoryName; + _Person = person; + _PossibleYear = possibleYear; + _RelativePath = relativePath; + } + + internal G2_Identify(Configuration configuration) + { + _DirectoryCount = 0; + _ParentDirectoryName = string.Empty; + _Person = string.Empty; + _PossibleYear = string.Empty; + _RelativePath = string.Empty; + _Configuration = configuration; + _Log = Serilog.Log.ForContext(); + _WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true }; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + + private FileInfo GetNamed() + { + FileInfo result; + string[] jsonFiles = Directory.GetFiles(_Configuration.PropertyConfiguration.RootDirectory, "*Named*.json", SearchOption.TopDirectoryOnly); + if (!jsonFiles.Any()) + result = null; + else + result = new FileInfo(jsonFiles[0]); + return result; + } + + private void CheckLastWriteTimes(Property.Models.Configuration configuration, IsEnvironment isEnvironment, A2_People a2People, FileInfo named, string g2IdentifySingletonDirectory) + { + string json; + FileInfo fileInfo; + DateTime dateTime = DateTime.MinValue; + string[] jsonFiles = Directory.GetFiles(g2IdentifySingletonDirectory, "*.json", SearchOption.AllDirectories); + foreach (string jsonFile in jsonFiles) + { + fileInfo = new(jsonFile); + if (dateTime < fileInfo.LastWriteTime) + dateTime = fileInfo.LastWriteTime; + } + if (named.LastWriteTime > dateTime) + { + if (!isEnvironment.DebuggerWasAttachedDuringConstructor) + throw new Exception("Only allowed when debugger is attached during constructor!"); + foreach (string file in jsonFiles) + File.Delete(file); + } + json = File.ReadAllText(named.FullName); + Person[] people = a2People.GetPeople(configuration); + Dictionary resultKeyValuePairs = new(); + string[] peopleBirthdates = (from l in people select Shared.Models.Stateless.Methods.IPersonBirthday.GetFormated(l.Birthday)).ToArray(); + Dictionary sourceKeyValuePairs = JsonSerializer.Deserialize>(json); + foreach (KeyValuePair keyValuePair in sourceKeyValuePairs) + { + if (!(from l in keyValuePair.Value where peopleBirthdates.Contains(l) select false).Any()) + continue; + resultKeyValuePairs.Add(keyValuePair.Key, keyValuePair.Value); + } + if (resultKeyValuePairs.Count != sourceKeyValuePairs.Count) + { + json = JsonSerializer.Serialize(resultKeyValuePairs, _WriteIndentedJsonSerializerOptions); + if (!isEnvironment.DebuggerWasAttachedDuringConstructor) + throw new Exception("Only allowed when debugger is attached during constructor!"); + _ = Property.Models.Stateless.IPath.WriteAllText(named.FullName, json, compareBeforeWrite: true); + } + } + + internal List GetIdentifiedCollection(Property.Models.Configuration configuration, IsEnvironment isEnvironment, A2_People a2People) + { + List results = new(); + string json; + string[] people; + string[] jsonFiles; + int directoryCount; + string possibleYear; + G2_Identify identify; + FileInfo named = GetNamed(); + string testDirectoryFullName; + string checkDirectoryFullName; + Dictionary keyValuePairs; + List missing = new(); + List indices = new(); + string directoryName = Path.GetFileName(_Configuration.PropertyConfiguration.RootDirectory); + string g2IdentifySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(G2_Identify), "[]"); + string jsonRootDirectory = Path.Combine(string.Concat(_Configuration.PropertyConfiguration.RootDirectory, " - Copied"), string.Concat(directoryName, " - 4) Info"), _Configuration.PropertyConfiguration.DateGroup, "[]"); + if (named is not null && named.Exists) + CheckLastWriteTimes(configuration, isEnvironment, a2People, named, g2IdentifySingletonDirectory); + if (Directory.Exists(jsonRootDirectory)) + { + jsonFiles = Directory.GetFiles(jsonRootDirectory, "*.json", SearchOption.AllDirectories); + for (int i = 0; i < jsonFiles.Length; i++) + { + json = Shared.Models.Stateless.Methods.IIndex.GetJson(jsonFiles[i], fileInfo: null); + indices.AddRange(JsonSerializer.Deserialize>(json)); + } + if (named is not null && named.Exists) + { + json = File.ReadAllText(named.FullName); + keyValuePairs = JsonSerializer.Deserialize>(json); + foreach (G_Index index in indices) + { + if (index?.Index is null) + continue; + if (!keyValuePairs.ContainsKey(index.Index.Value)) + { + missing.Add(index.Index.Value.ToString()); + continue; + } + if (index.RelativePaths is null) + { + missing.Add(index.Index.Value.ToString()); + continue; + } + people = keyValuePairs[index.Index.Value]; + foreach (string relativePath in index.RelativePaths) + { + foreach (string person in people) + { + directoryCount = 0; + checkDirectoryFullName = string.Concat(_Configuration.PropertyConfiguration.RootDirectory, relativePath); + for (int i = 0; i < int.MaxValue; i++) + { + testDirectoryFullName = Path.GetDirectoryName(checkDirectoryFullName); + if (testDirectoryFullName == _Configuration.PropertyConfiguration.RootDirectory) + break; + directoryCount += 1; + checkDirectoryFullName = testDirectoryFullName; + } + possibleYear = checkDirectoryFullName.Split(' ').Last(); + if (possibleYear.Length != 4) + possibleYear = "0000"; + identify = new G2_Identify(directoryCount, Path.GetFileName(checkDirectoryFullName), person, possibleYear, relativePath); + results.Add(identify); + } + } + } + } + } + results = (from l in results orderby l.PossibleYear descending, l.DirectoryCount, l.ParentDirectoryName, l.RelativePath select l).ToList(); + return results; + } + + internal void WriteAllText(Property.Models.Configuration configuration, string outputResolution, List identifiedCollection) + { + string key; + string json; + string jsonFile; + string directoryFullName; + string fileNameWithoutExtension; + string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "{}"); + string g2IdentifyCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(G2_Identify), "[]"); + Dictionary>> keyValuePairs = new(); + foreach (G2_Identify identified in identifiedCollection) + { + key = Path.GetDirectoryName(identified.RelativePath); + if (!keyValuePairs.ContainsKey(key)) + keyValuePairs.Add(key, new List>()); + keyValuePairs[key].Add(new KeyValuePair(identified.RelativePath, identified.Person)); + } + foreach (KeyValuePair>> keyValuePair in keyValuePairs) + { + directoryFullName = string.Concat(aPropertySingletonDirectory, keyValuePair.Key); + if (!Directory.Exists(directoryFullName)) + continue; + foreach (KeyValuePair keyValue in keyValuePair.Value) + { + fileNameWithoutExtension = Path.GetFileNameWithoutExtension(keyValue.Key); + jsonFile = Path.Combine(directoryFullName, $"{fileNameWithoutExtension}.json"); + if (!File.Exists(jsonFile)) + { + directoryFullName = string.Empty; + break; + } + } + if (string.IsNullOrEmpty(directoryFullName)) + continue; + directoryFullName = Path.GetDirectoryName(string.Concat(g2IdentifyCollectionDirectory, keyValuePair.Key)); + if (!Directory.Exists(directoryFullName)) + _ = Directory.CreateDirectory(directoryFullName); + jsonFile = string.Concat(g2IdentifyCollectionDirectory, keyValuePair.Key, ".json"); + json = JsonSerializer.Serialize(keyValuePair.Value, _WriteIndentedJsonSerializerOptions); + if (!Property.Models.Stateless.IPath.WriteAllText(jsonFile, json, compareBeforeWrite: true)) + continue; + } + } + +} \ No newline at end of file diff --git a/Instance/Models/_G_Index.cs b/Instance/Models/_G_Index.cs new file mode 100644 index 0000000..2a7ce52 --- /dev/null +++ b/Instance/Models/_G_Index.cs @@ -0,0 +1,213 @@ +using System.Text.Json; +using System.Text.Json.Serialization; +using View_by_Distance.Property.Models; +using View_by_Distance.Shared.Models.Methods; + +namespace View_by_Distance.Instance.Models; + +/// +// G_Index && G_Index[] +/// +public class G_Index : Shared.Models.Properties.IIndex, IIndex +{ + + private readonly Serilog.ILogger? _Log; + private readonly Configuration _Configuration; + private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions; + + protected DateTime? _DateTime; + protected int? _Index; + protected List _RelativePaths; + public DateTime? DateTime => _DateTime; + public int? Index => _Index; + public List RelativePaths => _RelativePaths; + +#nullable disable + [JsonConstructor] + public G_Index(DateTime? dateTime, int? index, List relativePaths) + { + _DateTime = dateTime; + _Index = index; + _RelativePaths = relativePaths; + } + + internal G_Index() + { + _DateTime = null; + _Index = null; + _RelativePaths = new(); + } + + internal G_Index(Configuration configuration) + { + _Configuration = configuration; + _Log = Serilog.Log.ForContext(); + _WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true }; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + + private G_Index GetIndexInfo(FileInfo fileInfo, List parseExceptions) + { + G_Index result; + List indices = new(); + string json = File.ReadAllText(fileInfo.FullName); + try + { + result = JsonSerializer.Deserialize(json); + } + catch (Exception) + { + result = null; + parseExceptions.Add(nameof(G_Index)); + } + if (_Configuration.MappedMaxIndex.HasValue && result.Index.HasValue && _Configuration.MappedMaxIndex.Value < result.Index.Value) + { + result = null; + File.Delete(fileInfo.FullName); + } + else if (result.Index is null) + result = null; + return result; + } + + private void WriteNeeded(List indices, List, string, A_Property>> neededTuples) + { + string json; + DateTime dateTime; + A_Property property; + G_Index indexInfo; + int maxIndexPlusOne; + DateTime?[] dateTimes; + if (indices.Any()) + maxIndexPlusOne = indices.Max() + 1; + else + { + maxIndexPlusOne = 1000000; + throw new Exception("Are you sure exception. Use debugger to step over."); + } + foreach (Tuple, string, A_Property> tuple in neededTuples) + { + maxIndexPlusOne += 1; + property = tuple.Item3; + dateTimes = new DateTime?[] { property.CreationTime, property.LastWriteTime, property.DateTime, property.DateTimeDigitized, property.DateTimeOriginal, property.GPSDateStamp }; + dateTime = (from l in dateTimes where l.HasValue select l.Value).Min(); + indexInfo = new(dateTime, maxIndexPlusOne, tuple.Item1); + json = JsonSerializer.Serialize(indexInfo, _WriteIndentedJsonSerializerOptions); + if (!Property.Models.Stateless.IPath.WriteAllText(tuple.Item2, json, compareBeforeWrite: true)) + continue; + } + } + + private void WriteGroup(Property.Models.Configuration configuration, string outputResolution, List>> indexInfoTuples) + { + string json; + G_Index[] indices; + List directoryInfoCollection; + foreach (Tuple> tuple in indexInfoTuples) + { + indices = (from l in tuple.Item2 select l.Value).ToArray(); + directoryInfoCollection = Property.Models.Stateless.IResult.GetDirectoryInfoCollection(configuration, tuple.Item1, nameof(G_Index), outputResolution, includeResizeGroup: false, includeModel: false, includePredictorModel: false, contentDescription: string.Empty, singletonDescription: string.Empty, collectionDescription: "Unknown A"); + json = JsonSerializer.Serialize(indices, _WriteIndentedJsonSerializerOptions); + if (!Property.Models.Stateless.IPath.WriteAllText(string.Concat(directoryInfoCollection[0].Replace("<>", "[]"), ".json"), json, compareBeforeWrite: true)) + continue; + } + } + + private void AppendTSV(Property.Models.Configuration configuration, string outputResolution, Dictionary>> filePropertiesKeyValuePairs) + { + A_Property property; + DateTime?[] dateTimes; + DateTime? maximumDateTime; + DateTime? minimumDateTime; + List directoryInfoCollection; + long ticks = System.DateTime.Now.Ticks; + foreach (KeyValuePair>> tuples in filePropertiesKeyValuePairs) + { + maximumDateTime = null; + minimumDateTime = null; + foreach (Tuple tuple in tuples.Value) + { + property = tuple.Item2; + dateTimes = new DateTime?[] { maximumDateTime, minimumDateTime, property.CreationTime, property.LastWriteTime, property.DateTime, property.DateTimeDigitized, property.DateTimeOriginal, property.GPSDateStamp }; + maximumDateTime = (from l in dateTimes where l.HasValue select l.Value).Max(); + minimumDateTime = (from l in dateTimes where l.HasValue select l.Value).Min(); + } + directoryInfoCollection = Property.Models.Stateless.IResult.GetDirectoryInfoCollection(configuration, tuples.Key, nameof(G_Index), outputResolution, includeResizeGroup: false, includeModel: false, includePredictorModel: false, contentDescription: string.Empty, singletonDescription: "Unkown B", collectionDescription: string.Empty); + } + } + + internal void SetIndex(Property.Models.Configuration configuration, string outputResolution, Dictionary>> filePropertiesKeyValuePairs) + { + if (_Configuration.PropertiesChangedForIndex is null) + throw new Exception(); + FileInfo fileInfo; + G_Index indexInfo; + string parentCheck; + List indices = new(); + Dictionary valuePairs; + List directoryInfoCollection; + List parseExceptions = new(); + List, string, A_Property>> neededTuples = new(); + List>> indexInfoTuples = new(); + for (short i = 0; i < short.MaxValue; i++) + { + if (i != 0) + { + if (!neededTuples.Any() && !parseExceptions.Any()) + break; + indices.Clear(); + indexInfoTuples.Clear(); + parseExceptions.Clear(); + } + neededTuples.Clear(); + foreach (KeyValuePair>> tuples in filePropertiesKeyValuePairs) + { + valuePairs = new Dictionary(); + directoryInfoCollection = Property.Models.Stateless.IResult.GetDirectoryInfoCollection(configuration, tuples.Key, nameof(G_Index), outputResolution, includeResizeGroup: false, includeModel: false, includePredictorModel: false, contentDescription: string.Empty, singletonDescription: "Unknown C", collectionDescription: string.Empty); + foreach (Tuple tuple in tuples.Value) + { + fileInfo = new FileInfo(Path.Combine(directoryInfoCollection[0].Replace("<>", "{}"), string.Concat(Path.GetFileNameWithoutExtension(tuple.Item1), ".json"))); + if (!fileInfo.Exists) + { + if (fileInfo.Directory?.Parent is null) + throw new Exception(); + parentCheck = Path.Combine(fileInfo.Directory.Parent.FullName, fileInfo.Name); + if (File.Exists(parentCheck)) + File.Delete(parentCheck); + } + if (_Configuration.PropertiesChangedForIndex.Value) + indexInfo = null; + else if (!fileInfo.Exists) + indexInfo = null; + else + indexInfo = GetIndexInfo(fileInfo, parseExceptions); + if (indexInfo?.Index is not null) + { + indices.Add(indexInfo.Index.Value); + valuePairs.Add(indexInfo.Index.Value, indexInfo); + } + else + neededTuples.Add(new Tuple, string, A_Property>(new List { tuple.Item1 }, fileInfo.FullName, tuple.Item2)); + } + indexInfoTuples.Add(new Tuple>(tuples.Key, valuePairs)); + } + if (_Configuration.MappedMaxIndex.HasValue) + break; + WriteNeeded(indices, neededTuples); + } + if (parseExceptions.Any()) + throw new Exception(string.Join(Environment.NewLine, parseExceptions)); + if (neededTuples.Any()) + throw new Exception(); + WriteGroup(configuration, outputResolution, indexInfoTuples); + AppendTSV(configuration, outputResolution, filePropertiesKeyValuePairs); + } + + string Shared.Models.Stateless.Methods.IIndex.TestStatic_GetJson(string jsonFileFullName, FileInfo fileInfo) => throw new NotImplementedException(); + +} \ No newline at end of file diff --git a/Instance/Program.cs b/Instance/Program.cs new file mode 100644 index 0000000..c485fd3 --- /dev/null +++ b/Instance/Program.cs @@ -0,0 +1,71 @@ +using Microsoft.Extensions.Configuration; +using Phares.Shared; +using Serilog; +using System.Diagnostics; +using System.Reflection; +using View_by_Distance.Instance.Models; +using View_by_Distance.Shared.Models.Stateless.Methods; + +namespace View_by_Distance.Instance; + +public class Program +{ + + public static void Secondary(List args) + { + LoggerConfiguration loggerConfiguration = new(); + Assembly assembly = Assembly.GetExecutingAssembly(); + bool debuggerWasAttachedAtLineZero = Debugger.IsAttached || assembly.Location.Contains(@"\bin\Debug"); + IsEnvironment isEnvironment = new(processesCount: null, nullASPNetCoreEnvironmentIsDevelopment: debuggerWasAttachedAtLineZero, nullASPNetCoreEnvironmentIsProduction: !debuggerWasAttachedAtLineZero); + IConfigurationBuilder configurationBuilder = new ConfigurationBuilder() + .AddEnvironmentVariables() + .AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true); + IConfigurationRoot configurationRoot = configurationBuilder.Build(); + AppSettings appSettings = Models.Stateless.AppSettings.Get(configurationRoot); + if (appSettings.MaxDegreeOfParallelism is null) + throw new Exception("MaxDegreeOfParallelism must be set!"); + if (appSettings.MaxDegreeOfParallelism.Value > Environment.ProcessorCount) + throw new Exception("MaxDegreeOfParallelism must be =< Environment.ProcessorCount!"); + if (string.IsNullOrEmpty(appSettings.WorkingDirectoryName)) + throw new Exception("Working directory name must have a value!"); + string workingDirectory = IWorkingDirectory.GetWorkingDirectory(assembly.GetName().Name, appSettings.WorkingDirectoryName); + Environment.SetEnvironmentVariable(nameof(workingDirectory), workingDirectory); + _ = ConfigurationLoggerConfigurationExtensions.Configuration(loggerConfiguration.ReadFrom, configurationRoot); + Log.Logger = loggerConfiguration.CreateLogger(); + ILogger log = Log.ForContext(); + int silentIndex = args.IndexOf("s"); + if (silentIndex > -1) + args.RemoveAt(silentIndex); + try + { + if (args is null) + throw new Exception("args is null!"); + Shared.Models.Console console = new(); + DlibDotNet _ = new(args, isEnvironment, configurationRoot, appSettings, workingDirectory, silentIndex > -1, console); + } + catch (Exception ex) + { + log.Fatal(string.Concat(ex.Message, Environment.NewLine, ex.StackTrace)); + } + finally + { + Log.CloseAndFlush(); + } + if (silentIndex > -1) + log.Debug("Done. Bye"); + else + { + log.Debug("Done. Press 'Enter' to end"); + _ = Console.ReadLine(); + } + } + + public static void Main(string[] args) + { + if (args is not null) + Secondary(args.ToList()); + else + Secondary(new List()); + } + +} \ No newline at end of file diff --git a/Instance/appsettings.Development.json b/Instance/appsettings.Development.json new file mode 100644 index 0000000..44715f6 --- /dev/null +++ b/Instance/appsettings.Development.json @@ -0,0 +1,457 @@ +{ + "Company": "Mike Phares", + "Linux": {}, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Log4netProvider": "Debug", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "MaxDegreeOfParallelism": 6, + "Serilog": { + "Using": [ + "Serilog.Sinks.Console", + "Serilog.Sinks.File" + ], + "MinimumLevel": "Debug", + "WriteTo": [ + { + "Name": "Debug", + "Args": { + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}" + } + }, + { + "Name": "Console", + "Args": { + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "%workingDirectory% - Log/log-.txt", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}", + "rollingInterval": "Hour" + } + } + ], + "Enrich": [ + "FromLogContext", + "WithMachineName", + "WithThreadId" + ], + "Properties": { + "Application": "Sample" + } + }, + "WorkingDirectoryName": "PharesApps", + "Windows": { + "Configuration": { + "CheckJsonForDistanceResults": true, + "CrossDirectoryMaxItemsInDistanceCollection": 7, + "DateGroup": "2022-04-07", + "DistanceFactor": 8, + "FileNameDirectorySeparator": ".Z.", + "ForceMetadataLastWriteTimeToCreationTime": false, + "ForcePropertyLastWriteTimeToCreationTime": false, + "ForceResizeLastWriteTimeToCreationTime": false, + "LoadOrCreateThenSaveDirectoryDistanceResults": true, + "LoadOrCreateThenSaveDistanceResults": true, + "LoadOrCreateThenSaveImageFacesResults": true, + "LoadOrCreateThenSaveIndex": false, + "LocationConfidenceFactor": 2, + "MappedMaxIndex": 1034720, + "MaxImagesInDirectoryForTopLevelFirstPass": 50, + "MaxItemsInDistanceCollection": 50, + "ModelDirectory": "C:/GitHub/dlib-models", + "ModelName": "Hog", + "NumJitters": 1, + "OutputExtension": ".jpg", + "OutputQuality": 95, + "OverrideForFaceImages": false, + "OverrideForFaceLandmarkImages": false, + "OverrideForResizeImages": false, + "PaddingLoops": 5, + "Pattern": "[^ABCDEFGHIJKLMNOPQRSTUVWXYZbcdfghjklmnpqrstvwxyz0-9]", + "PredictorModelName": "Large", + "PopulatePropertyId": true, + "PropertiesChangedForDistance": false, + "PropertiesChangedForFaces": false, + "PropertiesChangedForIndex": false, + "PropertiesChangedForMetadata": false, + "PropertiesChangedForProperty": false, + "PropertiesChangedForResize": false, + "Reverse": false, + "RootDirectory": "C:/Tmp/phares/Pictures", + "SaveFullYearOfRandomFiles": true, + "SaveResizedSubFiles": true, + "SearchForAbandonedFilesFull": true, + "SkipSearch": false, + "TestDistanceResults": true, + "WriteBitmapDataBytes": false, + "IgnoreExtensions": [ + ".gif", + ".GIF" + ], + "OutputResolutions": [ + "176 x 176", + "256 x 256", + "353 x 353", + "1024 x 768" + ], + "PropertyContentCollectionFiles": [], + "SaveFaceLandmarkForOutputResolutions": [ + "176 x 176", + "256 x 256" + ], + "ValidImageFormatExtensions": [ + ".bmp", + ".BMP", + ".gif", + ".GIF", + ".jpeg", + ".JPEG", + ".jpg", + ".JPG", + ".png", + ".PNG", + ".tiff", + ".TIFF" + ], + "ValidMetadataExtensions": [ + ".3gp", + ".3GP", + ".amr", + ".AMR", + ".avi", + ".AVI", + ".bmp", + ".BMP", + ".gif", + ".GIF", + ".ico", + ".ICO", + ".jpeg", + ".JPEG", + ".jpg", + ".JPG", + ".m4v", + ".M4V", + ".mov", + ".MOV", + ".mp4", + ".MP4", + ".mta", + ".MTA", + ".png", + ".PNG", + ".tiff", + ".TIFF" + ], + "ValidResolutions": [ + "176 x 176", + "256 x 256", + "353 x 353", + "1024 x 768", + "1280 x 720", + "1280 x 800", + "1376 x 768", + "1600 x 1200", + "1920 x 1080", + "2256 x 1496", + "3840 x 2160", + "7680 x 4320" + ], + "VerifyToSeason": [ + ". 2000", + ". 2001", + ". 2002", + ". 2003", + ". 2004", + ". 2005", + ". 2006", + ". 2007", + ". 2008", + ". 2009", + ". 2010", + ". 2011", + ". 2012", + ". 2013", + ". 2014", + ". 2015", + ". 2016", + ". 2017", + ". 2018", + ". 2019", + ". 2020", + ". 2021", + ". 2022", + ". 2023", + ". 2024", + ". 2025", + ". 2026", + ". 2027", + ". 2028", + ". 2029", + "=2000.0 Winter", + "=2002.1 Spring", + "=2002.4 Winter", + "=2003.0 Winter", + "=2003.1 Spring", + "=2003.3 Fall", + "=2003.4 Winter", + "=2004.0 Winter", + "=2005.1 Spring", + "=2005.2 Summer", + "=2005.3 Fall", + "=2005.4 Winter", + "=2006.0 Winter", + "=2006.1 Spring", + "=2006.3 Fall", + "=2007.0 Winter", + "=2007.2 Summer Logan Michael", + "=2007.2 Summer", + "=2007.3 Fall Logan Michael", + "=2007.4 Winter Logan Michael", + "=2008.0 Winter Logan Michael", + "=2008.1 Spring Logan Michael", + "=2008.2 Summer Logan Michael", + "=2008.2 Summer", + "=2008.3 Fall Logan Michael", + "=2009.0 Winter Logan Michael", + "=2009.0 Winter", + "=2009.1 Spring Logan Michael", + "=2009.1 Spring", + "=2009.2 Summer Logan Michael", + "=2009.2 Summer", + "=2009.3 Fall Logan Michael", + "=2009.3 Fall", + "=2009.4 Winter Logan Michael", + "=2009.4 Winter", + "=2010.0 Winter Logan Michael", + "=2010.0 Winter", + "=2010.1 Spring Logan Michael", + "=2010.1 Spring", + "=2010.2 Summer", + "=2010.3 Fall Logan Michael", + "=2010.3 Fall", + "=2010.4 Winter", + "=2011.0 Winter", + "=2011.1 Spring", + "=2011.2 Summer", + "=2011.3 Fall", + "=2011.4 Winter", + "=2012.0 Winter Chelsea 2012", + "=2012.0 Winter Chelsea", + "=2012.0 Winter", + "=2012.1 Spring Chelsea", + "=2012.1 Spring", + "=2012.2 Summer Chelsea", + "=2012.2 Summer", + "=2012.3 Fall Chelsea", + "=2012.3 Fall", + "=2012.4 Winter Chelsea", + "=2012.4 Winter", + "=2013.0 Winter Chelsea 2013", + "=2013.0 Winter Chelsea", + "=2013.0 Winter", + "=2013.1 Spring", + "=2013.2 Summer Chelsea", + "=2013.2 Summer", + "=2013.3 Fall Chelsea", + "=2013.3 Fall", + "=2013.4 Winter", + "=2014.0 Winter", + "=2014.1 Spring", + "=2014.2 Summer", + "=2014.3 Fall", + "=2014.4 Winter", + "=2015.0 Winter", + "=2015.1 Spring", + "=2015.2 Summer", + "=2015.3 Fall", + "=2015.4 Winter", + "=2016.0 Winter", + "=2016.1 Spring", + "=2016.2 Summer", + "=2016.3 Fall", + "=2016.4 Winter", + "=2017.1 Spring", + "=2017.2 Summer", + "=2017.3 Fall", + "=2017.4 Winter", + "=2018.0 Winter", + "=2018.1 Spring", + "=2018.3 Fall", + "=2018.4 Winter", + "=2019.0 Winter", + "=2019.1 Spring", + "=2019.2 Summer", + "=2019.3 Fall", + "=2019.4 Winter", + "=2020.0 Winter", + "=2020.1 Spring", + "=2020.2 Summer", + "=2020.3 Fall", + "=2020.4 Winter", + "=2021.1 Spring", + "=2021.2 Summer", + "=2021.3 Fall", + "=2021.4 Winter", + "=2022.0 Winter", + "=2022.1 Spring", + "Anthem 2015", + "April 2010", + "April 2013", + "December 2006", + "December 2010", + "Fall 2005", + "Fall 2015", + "Fall 2016", + "Fall 2017", + "Fall 2018", + "Fall 2019", + "Fall 2020", + "Fall 2021", + "February 2010", + "January 2015", + "July 2010", + "June 2010", + "Kids 2005", + "March 2013", + "May 2010", + "May 2011", + "May 2013", + "October 2005", + "October 2014", + "Spring 2013", + "Spring 2014", + "Spring 2016", + "Spring 2018", + "Spring 2019", + "Spring 2020", + "Summer 2011", + "Summer 2012", + "Summer 2013", + "Summer 2014", + "Summer 2015", + "Summer 2016", + "Summer 2017", + "Summer 2018", + "Summer 2020", + "Summer 2021", + "Winter 2015", + "Winter 2016", + "Winter 2017", + "Winter 2018", + "Winter 2019-2020", + "Winter 2020", + "zzz =2005.0 Winter Tracy Pictures", + "zzz =2005.1 Spring Tracy Pictures", + "zzz =2005.2 Summer Tracy Pictures", + "zzz =2005.3 Fall Tracy Pictures", + "zzz =2005.4 Winter Tracy Pictures", + "zzz =2006.1 Spring Tracy Pictures", + "zzz =2007.0 Winter Tracy Pictures", + "zzz =2007.2 Summer Tracy Pictures", + "zzz =2008.0 Winter Tracy Pictures", + "zzz =2008.2 Summer Tracy Pictures", + "zzz =2009.0 Winter Tracy Pictures", + "zzz =2009.2 Summer Tracy Pictures", + "zzz =2009.3 Fall Tracy Pictures", + "zzz =2009.4 Winter Tracy Pictures", + "zzz =2010.0 Winter Tracy Pictures", + "zzz =2010.1 Spring Tracy Pictures", + "zzz =2010.2 Summer Tracy Pictures", + "zzz =2010.3 Fall Tracy Pictures", + "zzz =2011.0 Winter Tracy Pictures", + "zzz =2011.1 Spring Tracy Pictures", + "zzz =2011.2 Summer Tracy Pictures", + "zzz =2011.3 Fall Tracy Pictures", + "zzz =2011.4 Winter Tracy Pictures", + "zzz =2012.0 Winter Tracy Pictures", + "zzz =2012.1 Spring Tracy Pictures", + "zzz =2012.2 Summer Tracy Pictures", + "zzz =2012.3 Fall Tracy Pictures", + "zzz =2012.4 Winter Tracy Pictures", + "zzz =2013.0 Winter Tracy Pictures", + "zzz =2013.1 Spring Tracy Pictures", + "zzz =2013.2 Summer Tracy Pictures", + "zzz =2013.3 Fall Tracy Pictures", + "zzz =2013.4 Winter Tracy Pictures", + "zzz =2014.0 Winter Tracy Pictures", + "zzz =2014.1 Spring Tracy Pictures", + "zzz =2014.2 Summer Tracy Pictures", + "zzz =2014.3 Fall Tracy Pictures", + "zzz =2014.4 Winter Tracy Pictures", + "zzz =2015.0 Winter Tracy Pictures" + ], + "MixedYearRelativePaths": [ + "Edited", + "Phares Slides", + "Rex Memorial", + "Scanned Grandma's Quilt", + "Scanned Pictures Of Kids", + "Scanned Prints", + "Slide in Name Order Originals (622)", + "Slides Pictures" + ], + "IgnoreRelativePaths": [ + "3757 W Whitman 2017", + "501 Playful Meadows 2006", + "501 Playful Meadows 2007", + "501 Playful Meadows 2008", + "501 Playful Meadows 2009", + "501 Playful Meadows 2010", + "501 Playful Meadows 2013", + "501 Playful Meadows 2015", + "6309 Evesham 2003", + "6309 Evesham 2004", + "Crystal's Wedding 2003", + "Danny's Wedding 2009", + "Door images 2019", + "Family Pictures 2006", + "Family Pictures 2007", + "Family Pictures 2011", + "Family Pictures 2013", + "GrandPrix 2004", + "Kids School Pictures 2004", + "Kristy 2002", + "Kristy Parents Wedding 2005", + "Logan Ultrasound 2007", + "Mandy's Dogs 2008", + "Motorcycles 2010", + "Motorcycles 2013", + "Motorcycles 2014", + "Phares Slides", + "Portrait Innovations April 2008", + "Portrait Innovations December 2007", + "Portrait Innovations June 2008", + "Portrait Innovations March 2012", + "The guys house 2000", + "Tracy Pictures 2005", + "Tracy Pictures 2006", + "Tracy Pictures 2007", + "Tracy Pictures 2008", + "Tracy Pictures 2009", + "Tracy Pictures 2010", + "Tracy Pictures 2011", + "Tracy Pictures 2012", + "Tracy Pictures 2013 Jan-July", + "Tracy Pictures 2013 July- Dec", + "Tracy Pictures 2014", + "Tracy Pictures 2015", + "Tracy Took The Kids 2006", + "Tracy's Bday 2012", + "Tracy's Wedding 2002", + "Trip to Colorado 10 2002", + "Trip to Colorado June 2002", + "Tub 2002", + "Vericruz 2011" + ] + } + } +} \ No newline at end of file diff --git a/Instance/appsettings.Staging.json b/Instance/appsettings.Staging.json new file mode 100644 index 0000000..e4860f7 --- /dev/null +++ b/Instance/appsettings.Staging.json @@ -0,0 +1,457 @@ +{ + "Company": "Mike Phares", + "Linux": {}, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Log4netProvider": "Information", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "MaxDegreeOfParallelism": 12, + "Serilog": { + "Using": [ + "Serilog.Sinks.Console", + "Serilog.Sinks.File" + ], + "MinimumLevel": "Debug", + "WriteTo": [ + { + "Name": "Debug", + "Args": { + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}" + } + }, + { + "Name": "Console", + "Args": { + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "%workingDirectory% - Log/log-.txt", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}", + "rollingInterval": "Hour" + } + } + ], + "Enrich": [ + "FromLogContext", + "WithMachineName", + "WithThreadId" + ], + "Properties": { + "Application": "Sample" + } + }, + "WorkingDirectoryName": "PharesApps", + "Windows": { + "Configuration": { + "CheckJsonForDistanceResults": true, + "CrossDirectoryMaxItemsInDistanceCollection": 7, + "DateGroup": "2022-04-07", + "DistanceFactor": 8, + "FileNameDirectorySeparator": ".Z.", + "ForceMetadataLastWriteTimeToCreationTime": false, + "ForcePropertyLastWriteTimeToCreationTime": false, + "ForceResizeLastWriteTimeToCreationTime": false, + "LoadOrCreateThenSaveDirectoryDistanceResults": false, + "LoadOrCreateThenSaveDistanceResults": false, + "LoadOrCreateThenSaveImageFacesResults": false, + "LoadOrCreateThenSaveIndex": false, + "LocationConfidenceFactor": 2, + "MappedMaxIndex": 1034720, + "MaxImagesInDirectoryForTopLevelFirstPass": 50, + "MaxItemsInDistanceCollection": 50, + "ModelDirectory": "L:/GitHub/dlib-models", + "ModelName": "Hog", + "NumJitters": 1, + "OutputExtension": ".jpg", + "OutputQuality": 95, + "OverrideForFaceImages": false, + "OverrideForFaceLandmarkImages": false, + "OverrideForResizeImages": false, + "PaddingLoops": 5, + "Pattern": "[^ABCDEFGHIJKLMNOPQRSTUVWXYZbcdfghjklmnpqrstvwxyz0-9]", + "PopulatePropertyId": true, + "PredictorModelName": "Large", + "PropertiesChangedForDistance": false, + "PropertiesChangedForFaces": false, + "PropertiesChangedForIndex": false, + "PropertiesChangedForMetadata": false, + "PropertiesChangedForProperty": false, + "PropertiesChangedForResize": false, + "Reverse": false, + "RootDirectory": "E:/Images", + "SaveFullYearOfRandomFiles": true, + "SaveResizedSubFiles": true, + "SearchForAbandonedFilesFull": false, + "SkipSearch": false, + "TestDistanceResults": true, + "WriteBitmapDataBytes": false, + "IgnoreExtensions": [ + ".gif", + ".GIF" + ], + "OutputResolutions": [ + "176 x 176", + "256 x 256", + "353 x 353", + "1024 x 768" + ], + "PropertyContentCollectionFiles": [], + "SaveFaceLandmarkForOutputResolutions": [ + "176 x 176", + "256 x 256" + ], + "ValidImageFormatExtensions": [ + ".bmp", + ".BMP", + ".gif", + ".GIF", + ".jpeg", + ".JPEG", + ".jpg", + ".JPG", + ".png", + ".PNG", + ".tiff", + ".TIFF" + ], + "ValidMetadataExtensions": [ + ".3gp", + ".3GP", + ".amr", + ".AMR", + ".avi", + ".AVI", + ".bmp", + ".BMP", + ".gif", + ".GIF", + ".ico", + ".ICO", + ".jpeg", + ".JPEG", + ".jpg", + ".JPG", + ".m4v", + ".M4V", + ".mov", + ".MOV", + ".mp4", + ".MP4", + ".mta", + ".MTA", + ".png", + ".PNG", + ".tiff", + ".TIFF" + ], + "ValidResolutions": [ + "176 x 176", + "256 x 256", + "353 x 353", + "1024 x 768", + "1280 x 720", + "1280 x 800", + "1376 x 768", + "1600 x 1200", + "1920 x 1080", + "2256 x 1496", + "3840 x 2160", + "7680 x 4320" + ], + "VerifyToSeason": [ + ". 2000", + ". 2001", + ". 2002", + ". 2003", + ". 2004", + ". 2005", + ". 2006", + ". 2007", + ". 2008", + ". 2009", + ". 2010", + ". 2011", + ". 2012", + ". 2013", + ". 2014", + ". 2015", + ". 2016", + ". 2017", + ". 2018", + ". 2019", + ". 2020", + ". 2021", + ". 2022", + ". 2023", + ". 2024", + ". 2025", + ". 2026", + ". 2027", + ". 2028", + ". 2029", + "=2000.0 Winter", + "=2002.1 Spring", + "=2002.4 Winter", + "=2003.0 Winter", + "=2003.1 Spring", + "=2003.3 Fall", + "=2003.4 Winter", + "=2004.0 Winter", + "=2005.1 Spring", + "=2005.2 Summer", + "=2005.3 Fall", + "=2005.4 Winter", + "=2006.0 Winter", + "=2006.1 Spring", + "=2006.3 Fall", + "=2007.0 Winter", + "=2007.2 Summer Logan Michael", + "=2007.2 Summer", + "=2007.3 Fall Logan Michael", + "=2007.4 Winter Logan Michael", + "=2008.0 Winter Logan Michael", + "=2008.1 Spring Logan Michael", + "=2008.2 Summer Logan Michael", + "=2008.2 Summer", + "=2008.3 Fall Logan Michael", + "=2009.0 Winter Logan Michael", + "=2009.0 Winter", + "=2009.1 Spring Logan Michael", + "=2009.1 Spring", + "=2009.2 Summer Logan Michael", + "=2009.2 Summer", + "=2009.3 Fall Logan Michael", + "=2009.3 Fall", + "=2009.4 Winter Logan Michael", + "=2009.4 Winter", + "=2010.0 Winter Logan Michael", + "=2010.0 Winter", + "=2010.1 Spring Logan Michael", + "=2010.1 Spring", + "=2010.2 Summer", + "=2010.3 Fall Logan Michael", + "=2010.3 Fall", + "=2010.4 Winter", + "=2011.0 Winter", + "=2011.1 Spring", + "=2011.2 Summer", + "=2011.3 Fall", + "=2011.4 Winter", + "=2012.0 Winter Chelsea 2012", + "=2012.0 Winter Chelsea", + "=2012.0 Winter", + "=2012.1 Spring Chelsea", + "=2012.1 Spring", + "=2012.2 Summer Chelsea", + "=2012.2 Summer", + "=2012.3 Fall Chelsea", + "=2012.3 Fall", + "=2012.4 Winter Chelsea", + "=2012.4 Winter", + "=2013.0 Winter Chelsea 2013", + "=2013.0 Winter Chelsea", + "=2013.0 Winter", + "=2013.1 Spring", + "=2013.2 Summer Chelsea", + "=2013.2 Summer", + "=2013.3 Fall Chelsea", + "=2013.3 Fall", + "=2013.4 Winter", + "=2014.0 Winter", + "=2014.1 Spring", + "=2014.2 Summer", + "=2014.3 Fall", + "=2014.4 Winter", + "=2015.0 Winter", + "=2015.1 Spring", + "=2015.2 Summer", + "=2015.3 Fall", + "=2015.4 Winter", + "=2016.0 Winter", + "=2016.1 Spring", + "=2016.2 Summer", + "=2016.3 Fall", + "=2016.4 Winter", + "=2017.1 Spring", + "=2017.2 Summer", + "=2017.3 Fall", + "=2017.4 Winter", + "=2018.0 Winter", + "=2018.1 Spring", + "=2018.3 Fall", + "=2018.4 Winter", + "=2019.0 Winter", + "=2019.1 Spring", + "=2019.2 Summer", + "=2019.3 Fall", + "=2019.4 Winter", + "=2020.0 Winter", + "=2020.1 Spring", + "=2020.2 Summer", + "=2020.3 Fall", + "=2020.4 Winter", + "=2021.1 Spring", + "=2021.2 Summer", + "=2021.3 Fall", + "=2021.4 Winter", + "=2022.0 Winter", + "=2022.1 Spring", + "Anthem 2015", + "April 2010", + "April 2013", + "December 2006", + "December 2010", + "Fall 2005", + "Fall 2015", + "Fall 2016", + "Fall 2017", + "Fall 2018", + "Fall 2019", + "Fall 2020", + "Fall 2021", + "February 2010", + "January 2015", + "July 2010", + "June 2010", + "Kids 2005", + "March 2013", + "May 2010", + "May 2011", + "May 2013", + "October 2005", + "October 2014", + "Spring 2013", + "Spring 2014", + "Spring 2016", + "Spring 2018", + "Spring 2019", + "Spring 2020", + "Summer 2011", + "Summer 2012", + "Summer 2013", + "Summer 2014", + "Summer 2015", + "Summer 2016", + "Summer 2017", + "Summer 2018", + "Summer 2020", + "Summer 2021", + "Winter 2015", + "Winter 2016", + "Winter 2017", + "Winter 2018", + "Winter 2019-2020", + "Winter 2020", + "zzz =2005.0 Winter Tracy Pictures", + "zzz =2005.1 Spring Tracy Pictures", + "zzz =2005.2 Summer Tracy Pictures", + "zzz =2005.3 Fall Tracy Pictures", + "zzz =2005.4 Winter Tracy Pictures", + "zzz =2006.1 Spring Tracy Pictures", + "zzz =2007.0 Winter Tracy Pictures", + "zzz =2007.2 Summer Tracy Pictures", + "zzz =2008.0 Winter Tracy Pictures", + "zzz =2008.2 Summer Tracy Pictures", + "zzz =2009.0 Winter Tracy Pictures", + "zzz =2009.2 Summer Tracy Pictures", + "zzz =2009.3 Fall Tracy Pictures", + "zzz =2009.4 Winter Tracy Pictures", + "zzz =2010.0 Winter Tracy Pictures", + "zzz =2010.1 Spring Tracy Pictures", + "zzz =2010.2 Summer Tracy Pictures", + "zzz =2010.3 Fall Tracy Pictures", + "zzz =2011.0 Winter Tracy Pictures", + "zzz =2011.1 Spring Tracy Pictures", + "zzz =2011.2 Summer Tracy Pictures", + "zzz =2011.3 Fall Tracy Pictures", + "zzz =2011.4 Winter Tracy Pictures", + "zzz =2012.0 Winter Tracy Pictures", + "zzz =2012.1 Spring Tracy Pictures", + "zzz =2012.2 Summer Tracy Pictures", + "zzz =2012.3 Fall Tracy Pictures", + "zzz =2012.4 Winter Tracy Pictures", + "zzz =2013.0 Winter Tracy Pictures", + "zzz =2013.1 Spring Tracy Pictures", + "zzz =2013.2 Summer Tracy Pictures", + "zzz =2013.3 Fall Tracy Pictures", + "zzz =2013.4 Winter Tracy Pictures", + "zzz =2014.0 Winter Tracy Pictures", + "zzz =2014.1 Spring Tracy Pictures", + "zzz =2014.2 Summer Tracy Pictures", + "zzz =2014.3 Fall Tracy Pictures", + "zzz =2014.4 Winter Tracy Pictures", + "zzz =2015.0 Winter Tracy Pictures" + ], + "MixedYearRelativePaths": [ + "Edited", + "Phares Slides", + "Rex Memorial", + "Scanned Grandma's Quilt", + "Scanned Pictures Of Kids", + "Scanned Prints", + "Slide in Name Order Originals (622)", + "Slides Pictures" + ], + "IgnoreRelativePaths": [ + "3757 W Whitman 2017", + "501 Playful Meadows 2006", + "501 Playful Meadows 2007", + "501 Playful Meadows 2008", + "501 Playful Meadows 2009", + "501 Playful Meadows 2010", + "501 Playful Meadows 2013", + "501 Playful Meadows 2015", + "6309 Evesham 2003", + "6309 Evesham 2004", + "Crystal's Wedding 2003", + "Danny's Wedding 2009", + "Door images 2019", + "Family Pictures 2006", + "Family Pictures 2007", + "Family Pictures 2011", + "Family Pictures 2013", + "GrandPrix 2004", + "Kids School Pictures 2004", + "Kristy 2002", + "Kristy Parents Wedding 2005", + "Logan Ultrasound 2007", + "Mandy's Dogs 2008", + "Motorcycles 2010", + "Motorcycles 2013", + "Motorcycles 2014", + "Phares Slides", + "Portrait Innovations April 2008", + "Portrait Innovations December 2007", + "Portrait Innovations June 2008", + "Portrait Innovations March 2012", + "The guys house 2000", + "Tracy Pictures 2005", + "Tracy Pictures 2006", + "Tracy Pictures 2007", + "Tracy Pictures 2008", + "Tracy Pictures 2009", + "Tracy Pictures 2010", + "Tracy Pictures 2011", + "Tracy Pictures 2012", + "Tracy Pictures 2013 Jan-July", + "Tracy Pictures 2013 July- Dec", + "Tracy Pictures 2014", + "Tracy Pictures 2015", + "Tracy Took The Kids 2006", + "Tracy's Bday 2012", + "Tracy's Wedding 2002", + "Trip to Colorado 10 2002", + "Trip to Colorado June 2002", + "Tub 2002", + "Vericruz 2011" + ] + } + } +} \ No newline at end of file diff --git a/Instance/appsettings.json b/Instance/appsettings.json new file mode 100644 index 0000000..cc6fe1b --- /dev/null +++ b/Instance/appsettings.json @@ -0,0 +1,458 @@ +{ + "Company": "Mike Phares", + "Linux": {}, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Log4netProvider": "Information", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "MaxDegreeOfParallelism": 12, + "Serilog": { + "Using": [ + "Serilog.Sinks.Console", + "Serilog.Sinks.File" + ], + "MinimumLevel": "Debug", + "WriteTo": [ + { + "Name": "Debug", + "Args": { + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}" + } + }, + { + "Name": "Console", + "Args": { + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "%workingDirectory% - Log/log-.txt", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}", + "rollingInterval": "Hour" + } + } + ], + "Enrich": [ + "FromLogContext", + "WithMachineName", + "WithThreadId" + ], + "Properties": { + "Application": "Sample" + } + }, + "WorkingDirectoryName": "PharesApps", + "Windows": { + "Configuration": { + "CheckJsonForDistanceResults": true, + "CrossDirectoryMaxItemsInDistanceCollection": 7, + "DateGroup": "2022-04-07", + "DistanceFactor": 8, + "FileNameDirectorySeparator": ".Z.", + "ForceMetadataLastWriteTimeToCreationTime": false, + "ForcePropertyLastWriteTimeToCreationTime": false, + "ForceResizeLastWriteTimeToCreationTime": false, + "LoadOrCreateThenSaveDirectoryDistanceResults": true, + "LoadOrCreateThenSaveDistanceResults": true, + "LoadOrCreateThenSaveImageFacesResults": true, + "LoadOrCreateThenSaveIndex": false, + "LocationConfidenceFactor": 2, + "MappedMaxIndex": 1034720, + "MaxImagesInDirectoryForTopLevelFirstPass": 50, + "MaxItemsInDistanceCollection": 50, + "ModelDirectory": "C:/GitHub/dlib-models", + "ModelName": "Hog", + "NumJitters": 1, + "OutputExtension": ".jpg", + "OutputQuality": 95, + "OverrideForFaceImages": false, + "OverrideForFaceLandmarkImages": false, + "OverrideForResizeImages": false, + "PaddingLoops": 5, + "Pattern": "[^ABCDEFGHIJKLMNOPQRSTUVWXYZbcdfghjklmnpqrstvwxyz0-9]", + "PopulatePropertyId": true, + "PredictorModelName": "Large", + "PropertiesChangedForDistance": false, + "PropertiesChangedForFaces": false, + "PropertiesChangedForIndex": false, + "PropertiesChangedForMetadata": false, + "PropertiesChangedForProperty": false, + "PropertiesChangedForResize": false, + "Reverse": false, + "RootDirectory": "D:/Images", + "SaveFullYearOfRandomFiles": true, + "SaveResizedSubFiles": true, + "SearchForAbandonedFilesFull": false, + "SkipSearch": false, + "TestDistanceResults": true, + "WriteBitmapDataBytes": false, + "IgnoreExtensions": [ + ".gif", + ".GIF" + ], + "OutputResolutions": [ + "176 x 176", + "256 x 256", + "353 x 353", + "1024 x 768", + "1920 x 1080" + ], + "PropertyContentCollectionFiles": [], + "SaveFaceLandmarkForOutputResolutions": [ + "176 x 176", + "256 x 256" + ], + "ValidImageFormatExtensions": [ + ".bmp", + ".BMP", + ".gif", + ".GIF", + ".jpeg", + ".JPEG", + ".jpg", + ".JPG", + ".png", + ".PNG", + ".tiff", + ".TIFF" + ], + "ValidMetadataExtensions": [ + ".3gp", + ".3GP", + ".amr", + ".AMR", + ".avi", + ".AVI", + ".bmp", + ".BMP", + ".gif", + ".GIF", + ".ico", + ".ICO", + ".jpeg", + ".JPEG", + ".jpg", + ".JPG", + ".m4v", + ".M4V", + ".mov", + ".MOV", + ".mp4", + ".MP4", + ".mta", + ".MTA", + ".png", + ".PNG", + ".tiff", + ".TIFF" + ], + "ValidResolutions": [ + "176 x 176", + "256 x 256", + "353 x 353", + "1024 x 768", + "1280 x 720", + "1280 x 800", + "1376 x 768", + "1600 x 1200", + "1920 x 1080", + "2256 x 1496", + "3840 x 2160", + "7680 x 4320" + ], + "VerifyToSeason": [ + ". 2000", + ". 2001", + ". 2002", + ". 2003", + ". 2004", + ". 2005", + ". 2006", + ". 2007", + ". 2008", + ". 2009", + ". 2010", + ". 2011", + ". 2012", + ". 2013", + ". 2014", + ". 2015", + ". 2016", + ". 2017", + ". 2018", + ". 2019", + ". 2020", + ". 2021", + ". 2022", + ". 2023", + ". 2024", + ". 2025", + ". 2026", + ". 2027", + ". 2028", + ". 2029", + "=2000.0 Winter", + "=2002.1 Spring", + "=2002.4 Winter", + "=2003.0 Winter", + "=2003.1 Spring", + "=2003.3 Fall", + "=2003.4 Winter", + "=2004.0 Winter", + "=2005.1 Spring", + "=2005.2 Summer", + "=2005.3 Fall", + "=2005.4 Winter", + "=2006.0 Winter", + "=2006.1 Spring", + "=2006.3 Fall", + "=2007.0 Winter", + "=2007.2 Summer Logan Michael", + "=2007.2 Summer", + "=2007.3 Fall Logan Michael", + "=2007.4 Winter Logan Michael", + "=2008.0 Winter Logan Michael", + "=2008.1 Spring Logan Michael", + "=2008.2 Summer Logan Michael", + "=2008.2 Summer", + "=2008.3 Fall Logan Michael", + "=2009.0 Winter Logan Michael", + "=2009.0 Winter", + "=2009.1 Spring Logan Michael", + "=2009.1 Spring", + "=2009.2 Summer Logan Michael", + "=2009.2 Summer", + "=2009.3 Fall Logan Michael", + "=2009.3 Fall", + "=2009.4 Winter Logan Michael", + "=2009.4 Winter", + "=2010.0 Winter Logan Michael", + "=2010.0 Winter", + "=2010.1 Spring Logan Michael", + "=2010.1 Spring", + "=2010.2 Summer", + "=2010.3 Fall Logan Michael", + "=2010.3 Fall", + "=2010.4 Winter", + "=2011.0 Winter", + "=2011.1 Spring", + "=2011.2 Summer", + "=2011.3 Fall", + "=2011.4 Winter", + "=2012.0 Winter Chelsea 2012", + "=2012.0 Winter Chelsea", + "=2012.0 Winter", + "=2012.1 Spring Chelsea", + "=2012.1 Spring", + "=2012.2 Summer Chelsea", + "=2012.2 Summer", + "=2012.3 Fall Chelsea", + "=2012.3 Fall", + "=2012.4 Winter Chelsea", + "=2012.4 Winter", + "=2013.0 Winter Chelsea 2013", + "=2013.0 Winter Chelsea", + "=2013.0 Winter", + "=2013.1 Spring", + "=2013.2 Summer Chelsea", + "=2013.2 Summer", + "=2013.3 Fall Chelsea", + "=2013.3 Fall", + "=2013.4 Winter", + "=2014.0 Winter", + "=2014.1 Spring", + "=2014.2 Summer", + "=2014.3 Fall", + "=2014.4 Winter", + "=2015.0 Winter", + "=2015.1 Spring", + "=2015.2 Summer", + "=2015.3 Fall", + "=2015.4 Winter", + "=2016.0 Winter", + "=2016.1 Spring", + "=2016.2 Summer", + "=2016.3 Fall", + "=2016.4 Winter", + "=2017.1 Spring", + "=2017.2 Summer", + "=2017.3 Fall", + "=2017.4 Winter", + "=2018.0 Winter", + "=2018.1 Spring", + "=2018.3 Fall", + "=2018.4 Winter", + "=2019.0 Winter", + "=2019.1 Spring", + "=2019.2 Summer", + "=2019.3 Fall", + "=2019.4 Winter", + "=2020.0 Winter", + "=2020.1 Spring", + "=2020.2 Summer", + "=2020.3 Fall", + "=2020.4 Winter", + "=2021.1 Spring", + "=2021.2 Summer", + "=2021.3 Fall", + "=2021.4 Winter", + "=2022.0 Winter", + "=2022.1 Spring", + "Anthem 2015", + "April 2010", + "April 2013", + "December 2006", + "December 2010", + "Fall 2005", + "Fall 2015", + "Fall 2016", + "Fall 2017", + "Fall 2018", + "Fall 2019", + "Fall 2020", + "Fall 2021", + "February 2010", + "January 2015", + "July 2010", + "June 2010", + "Kids 2005", + "March 2013", + "May 2010", + "May 2011", + "May 2013", + "October 2005", + "October 2014", + "Spring 2013", + "Spring 2014", + "Spring 2016", + "Spring 2018", + "Spring 2019", + "Spring 2020", + "Summer 2011", + "Summer 2012", + "Summer 2013", + "Summer 2014", + "Summer 2015", + "Summer 2016", + "Summer 2017", + "Summer 2018", + "Summer 2020", + "Summer 2021", + "Winter 2015", + "Winter 2016", + "Winter 2017", + "Winter 2018", + "Winter 2019-2020", + "Winter 2020", + "zzz =2005.0 Winter Tracy Pictures", + "zzz =2005.1 Spring Tracy Pictures", + "zzz =2005.2 Summer Tracy Pictures", + "zzz =2005.3 Fall Tracy Pictures", + "zzz =2005.4 Winter Tracy Pictures", + "zzz =2006.1 Spring Tracy Pictures", + "zzz =2007.0 Winter Tracy Pictures", + "zzz =2007.2 Summer Tracy Pictures", + "zzz =2008.0 Winter Tracy Pictures", + "zzz =2008.2 Summer Tracy Pictures", + "zzz =2009.0 Winter Tracy Pictures", + "zzz =2009.2 Summer Tracy Pictures", + "zzz =2009.3 Fall Tracy Pictures", + "zzz =2009.4 Winter Tracy Pictures", + "zzz =2010.0 Winter Tracy Pictures", + "zzz =2010.1 Spring Tracy Pictures", + "zzz =2010.2 Summer Tracy Pictures", + "zzz =2010.3 Fall Tracy Pictures", + "zzz =2011.0 Winter Tracy Pictures", + "zzz =2011.1 Spring Tracy Pictures", + "zzz =2011.2 Summer Tracy Pictures", + "zzz =2011.3 Fall Tracy Pictures", + "zzz =2011.4 Winter Tracy Pictures", + "zzz =2012.0 Winter Tracy Pictures", + "zzz =2012.1 Spring Tracy Pictures", + "zzz =2012.2 Summer Tracy Pictures", + "zzz =2012.3 Fall Tracy Pictures", + "zzz =2012.4 Winter Tracy Pictures", + "zzz =2013.0 Winter Tracy Pictures", + "zzz =2013.1 Spring Tracy Pictures", + "zzz =2013.2 Summer Tracy Pictures", + "zzz =2013.3 Fall Tracy Pictures", + "zzz =2013.4 Winter Tracy Pictures", + "zzz =2014.0 Winter Tracy Pictures", + "zzz =2014.1 Spring Tracy Pictures", + "zzz =2014.2 Summer Tracy Pictures", + "zzz =2014.3 Fall Tracy Pictures", + "zzz =2014.4 Winter Tracy Pictures", + "zzz =2015.0 Winter Tracy Pictures" + ], + "MixedYearRelativePaths": [ + "Edited", + "Phares Slides", + "Rex Memorial", + "Scanned Grandma's Quilt", + "Scanned Pictures Of Kids", + "Scanned Prints", + "Slide in Name Order Originals (622)", + "Slides Pictures" + ], + "IgnoreRelativePaths": [ + "3757 W Whitman 2017", + "501 Playful Meadows 2006", + "501 Playful Meadows 2007", + "501 Playful Meadows 2008", + "501 Playful Meadows 2009", + "501 Playful Meadows 2010", + "501 Playful Meadows 2013", + "501 Playful Meadows 2015", + "6309 Evesham 2003", + "6309 Evesham 2004", + "Crystal's Wedding 2003", + "Danny's Wedding 2009", + "Door images 2019", + "Family Pictures 2006", + "Family Pictures 2007", + "Family Pictures 2011", + "Family Pictures 2013", + "GrandPrix 2004", + "Kids School Pictures 2004", + "Kristy 2002", + "Kristy Parents Wedding 2005", + "Logan Ultrasound 2007", + "Mandy's Dogs 2008", + "Motorcycles 2010", + "Motorcycles 2013", + "Motorcycles 2014", + "Phares Slides", + "Portrait Innovations April 2008", + "Portrait Innovations December 2007", + "Portrait Innovations June 2008", + "Portrait Innovations March 2012", + "The guys house 2000", + "Tracy Pictures 2005", + "Tracy Pictures 2006", + "Tracy Pictures 2007", + "Tracy Pictures 2008", + "Tracy Pictures 2009", + "Tracy Pictures 2010", + "Tracy Pictures 2011", + "Tracy Pictures 2012", + "Tracy Pictures 2013 Jan-July", + "Tracy Pictures 2013 July- Dec", + "Tracy Pictures 2014", + "Tracy Pictures 2015", + "Tracy Took The Kids 2006", + "Tracy's Bday 2012", + "Tracy's Wedding 2002", + "Trip to Colorado 10 2002", + "Trip to Colorado June 2002", + "Tub 2002", + "Vericruz 2011" + ] + } + } +} \ No newline at end of file diff --git a/Metadata/.vscode/settings.json b/Metadata/.vscode/settings.json new file mode 100644 index 0000000..8c8a882 --- /dev/null +++ b/Metadata/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "cSpell.words": [ + "dlib", + "Exif", + "Serilog" + ] +} \ No newline at end of file diff --git a/Metadata/Metadata.csproj b/Metadata/Metadata.csproj new file mode 100644 index 0000000..bd86b21 --- /dev/null +++ b/Metadata/Metadata.csproj @@ -0,0 +1,47 @@ + + + enable + 10.0 + enable + library + win-x64 + net6.0 + + + Phares.View.by.Distance.Metadata + false + 5.0.402.104 + Mike Phares + Phares + true + snupkg + + + true + true + true + + + Windows + + + OSX + + + Linux + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Metadata/Models/B_Metadata.cs b/Metadata/Models/B_Metadata.cs new file mode 100644 index 0000000..dd749a8 --- /dev/null +++ b/Metadata/Models/B_Metadata.cs @@ -0,0 +1,181 @@ +using System.Diagnostics; +using System.Text.Json; +using View_by_Distance.Metadata.Models.Stateless; +using View_by_Distance.Shared.Models.Stateless; + +namespace View_by_Distance.Metadata.Models; + +/// +// Dictionary>> +/// +public class B_Metadata +{ + + public List AngleBracketCollection { get; } + + private readonly Serilog.ILogger? _Log; + private readonly bool _PropertiesChangedForMetadata; + private readonly bool _ForceMetadataLastWriteTimeToCreationTime; + private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions; + + public static string DateTimeFormat() => "ddd MMM dd HH:mm:ss yyyy"; + + public B_Metadata(bool forceMetadataLastWriteTimeToCreationTime, bool propertiesChangedForMetadata) + { + AngleBracketCollection = new List(); + _Log = Serilog.Log.ForContext(); + _PropertiesChangedForMetadata = propertiesChangedForMetadata; + _ForceMetadataLastWriteTimeToCreationTime = forceMetadataLastWriteTimeToCreationTime; + _WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true }; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + + private Dictionary>> GetMetadataCollection(string subFile) + { + Dictionary>> results = new(); + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + try + { + object? @object; + string? tagDescription; + int type = (int)IExif.Tags.Orientation; + List tagNames = new(); + string key = nameof(IExif.Tags.Orientation); + IReadOnlyList directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(subFile); + foreach (MetadataExtractor.Directory directory in directories) + { + if (!results.ContainsKey(directory.Name)) + results.Add(directory.Name, new()); + foreach (MetadataExtractor.Tag tag in directory.Tags) + { + tagNames.Add(tag.Name); + if (string.IsNullOrEmpty(tag.Description)) + continue; + results[directory.Name].Add(new KeyValuePair(string.Concat(tag.Type, '\t', tag.Name), tag.Description)); + } + if (tagNames.Contains(key) && !results.ContainsKey(key)) + { + @object = directory.GetObject(type); + if (@object is null) + continue; + tagDescription = @object.ToString(); + if (string.IsNullOrEmpty(tagDescription)) + continue; + results.Add(key, new() { new(string.Concat(type, '\t', key), tagDescription) }); + } + } + } + catch (Exception) + { + _Log.Info(string.Concat(new StackFrame().GetMethod()?.Name, " <", subFile, ">")); + } + return results; + } + + public (int, List>) GetMetadataCollection(List> subFileTuples, List parseExceptions, string subFile, string relativePath, string fileNameWithoutExtension) + { + List> results = new(); + Dictionary>>? dictionary; + string json = string.Empty; + string[] changesFrom = Array.Empty(); + List dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); + FileInfo fileInfo = new(Path.Combine(AngleBracketCollection[0].Replace("<>", "{}"), string.Concat(fileNameWithoutExtension, ".json"))); + if (!fileInfo.Exists) + { + if (fileInfo.Directory?.Parent is null) + throw new Exception(); + string parentCheck = Path.Combine(fileInfo.Directory.Parent.FullName, fileInfo.Name); + if (File.Exists(parentCheck)) + { + File.Move(parentCheck, fileInfo.FullName); + fileInfo.Refresh(); + } + } + if (_ForceMetadataLastWriteTimeToCreationTime && !fileInfo.Exists && File.Exists(Path.ChangeExtension(fileInfo.FullName, ".delete"))) + { + File.Move(Path.ChangeExtension(fileInfo.FullName, ".delete"), fileInfo.FullName); + fileInfo.Refresh(); + } + if (_ForceMetadataLastWriteTimeToCreationTime && fileInfo.Exists && fileInfo.LastWriteTime != fileInfo.CreationTime) + { + File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime); + fileInfo.Refresh(); + } + if (_PropertiesChangedForMetadata) + dictionary = new(); + else if (!fileInfo.Exists) + dictionary = new(); + else if (dateTimes.Any() && dateTimes.Max() > fileInfo.LastWriteTime) + dictionary = new(); + else + { + json = File.ReadAllText(fileInfo.FullName); + try + { + dictionary = JsonSerializer.Deserialize>>>(json); + if (dictionary is null) + throw new Exception(); + subFileTuples.Add(new Tuple(nameof(B_Metadata), fileInfo.LastWriteTime)); + } + catch (Exception) + { + dictionary = new(); + parseExceptions.Add(nameof(B_Metadata)); + } + } + if (dictionary is null || !dictionary.Any()) + { + dictionary = GetMetadataCollection(subFile); + json = JsonSerializer.Serialize(dictionary, _WriteIndentedJsonSerializerOptions); + if (Property.Models.Stateless.IPath.WriteAllText(fileInfo.FullName, json, compareBeforeWrite: true)) + { + if (!_ForceMetadataLastWriteTimeToCreationTime && (!fileInfo.Exists || fileInfo.LastWriteTime == fileInfo.CreationTime)) + subFileTuples.Add(new Tuple(nameof(B_Metadata), DateTime.Now)); + else + { + File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime); + fileInfo.Refresh(); + subFileTuples.Add(new Tuple(nameof(B_Metadata), fileInfo.CreationTime)); + } + } + } + foreach (KeyValuePair>> keyValuePair in dictionary) + { + foreach (KeyValuePair keyValue in keyValuePair.Value) + results.Add(new(string.Concat(keyValuePair.Key, '\t', keyValue.Key), keyValue.Value)); + } + return new(dictionary.Count, results); + } + + public static List> GetFiltered(List> metadataCollection) + { + List> results = new(); + foreach (KeyValuePair keyValuePair in metadataCollection) + { + if (keyValuePair.Key.Contains("File") || keyValuePair.Key.Contains("JPEG") || keyValuePair.Key.Contains("Orientation") || keyValuePair.Key.Contains("Thumbnail")) + continue; + results.Add(new(keyValuePair.Key, keyValuePair.Value)); + } + if (!results.Any()) + results = metadataCollection; + return results; + } + + public static string GetUniqueImageId(List> metadataCollection) + { + string result = string.Empty; + const string exifSubIFD = "Exif SubIFD"; + const string uniqueImageID = "42016\tUnique Image ID"; + List uniqueImageIDs = (from l in metadataCollection where l.Key.StartsWith(exifSubIFD) && l.Key.EndsWith(uniqueImageID) select l.Value).ToList(); + if (uniqueImageIDs.Any()) + result = uniqueImageIDs[0]; + return result; + } + +} \ No newline at end of file diff --git a/Metadata/Models/Stateless/SerilogExtensionMethods.cs b/Metadata/Models/Stateless/SerilogExtensionMethods.cs new file mode 100644 index 0000000..4126243 --- /dev/null +++ b/Metadata/Models/Stateless/SerilogExtensionMethods.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Metadata.Models.Stateless; + +internal static class SerilogExtensionMethods +{ + + internal static void Warn(this Serilog.ILogger log, string messageTemplate) => log.Warning(messageTemplate); + + internal static void Info(this Serilog.ILogger log, string messageTemplate) => log.Information(messageTemplate); + +} \ No newline at end of file diff --git a/Not-Copy-Copy/.vscode/format-report.json b/Not-Copy-Copy/.vscode/format-report.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/Not-Copy-Copy/.vscode/format-report.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/Not-Copy-Copy/.vscode/launch.json b/Not-Copy-Copy/.vscode/launch.json new file mode 100644 index 0000000..0bcf080 --- /dev/null +++ b/Not-Copy-Copy/.vscode/launch.json @@ -0,0 +1,30 @@ +{ + "version": "0.2.0", + "configurations": [ + { + // Use IntelliSense to find out which attributes exist for C# debugging + // Use hover for the description of the existing attributes + // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md + "name": ".NET Core Launch (console)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + // If you have changed target frameworks, make sure to update the program path. + "program": "${workspaceFolder}/bin/Debug/net6.0/win-x64/Not-Copy-Copy.dll", + "args": [], + "env": { + "ASPNETCORE_ENVIRONMENT": "Development", + }, + "cwd": "${workspaceFolder}", + // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console + "console": "externalTerminal", + "stopAtEntry": false + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach", + "processName": "Not-Copy-Copy" + } + ] +} \ No newline at end of file diff --git a/Not-Copy-Copy/.vscode/settings.json b/Not-Copy-Copy/.vscode/settings.json new file mode 100644 index 0000000..09ac856 --- /dev/null +++ b/Not-Copy-Copy/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "cSpell.words": [ + "Barrick", + "Beichler", + "Bohdi", + "Dlib", + "Phares", + "Serilog", + "Vericruz" + ] +} \ No newline at end of file diff --git a/Not-Copy-Copy/.vscode/tasks.json b/Not-Copy-Copy/.vscode/tasks.json new file mode 100644 index 0000000..0154bfa --- /dev/null +++ b/Not-Copy-Copy/.vscode/tasks.json @@ -0,0 +1,42 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/Not-Copy-Copy.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "publish", + "command": "dotnet", + "type": "process", + "args": [ + "publish", + "${workspaceFolder}/Not-Copy-Copy.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "watch", + "command": "dotnet", + "type": "process", + "args": [ + "watch", + "run", + "${workspaceFolder}/Not-Copy-Copy.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/Not-Copy-Copy/Models/AppSettings.cs b/Not-Copy-Copy/Models/AppSettings.cs new file mode 100644 index 0000000..994a295 --- /dev/null +++ b/Not-Copy-Copy/Models/AppSettings.cs @@ -0,0 +1,35 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Not.Copy.Copy.Models; + +public class AppSettings +{ + + protected string _Company; + protected string _WorkingDirectoryName; + protected int? _MaxDegreeOfParallelism; + public string Company => _Company; + public string WorkingDirectoryName => _WorkingDirectoryName; + public int? MaxDegreeOfParallelism => _MaxDegreeOfParallelism; + + // public AppSettings() + // { + + // } + + [JsonConstructor] + public AppSettings(string company, string workingDirectoryName, int? maxDegreeOfParallelism) + { + _Company = company; + _WorkingDirectoryName = workingDirectoryName; + _MaxDegreeOfParallelism = maxDegreeOfParallelism; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/Not-Copy-Copy/Models/Binder/AppSettings.cs b/Not-Copy-Copy/Models/Binder/AppSettings.cs new file mode 100644 index 0000000..bf7052f --- /dev/null +++ b/Not-Copy-Copy/Models/Binder/AppSettings.cs @@ -0,0 +1,26 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.Json; + +namespace View_by_Distance.Not.Copy.Copy.Models.Binder; + +public class AppSettings +{ + + [Display(Name = "Company"), Required] public string Company { get; set; } + [Display(Name = "Working Directory Name"), Required] public string WorkingDirectoryName { get; set; } + [Display(Name = "Max Degree Of Parallelism"), Required] public int? MaxDegreeOfParallelism { get; set; } + + public AppSettings() + { + Company = string.Empty; + WorkingDirectoryName = string.Empty; + MaxDegreeOfParallelism = -1; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/Not-Copy-Copy/Models/Binder/Configuration.cs b/Not-Copy-Copy/Models/Binder/Configuration.cs new file mode 100644 index 0000000..8ae74dd --- /dev/null +++ b/Not-Copy-Copy/Models/Binder/Configuration.cs @@ -0,0 +1,27 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.Json; + +namespace View_by_Distance.Not.Copy.Copy.Models.Binder; + +public class Configuration +{ + + [Display(Name = "Compare Source"), Required] public string CompareSource { get; set; } + [Display(Name = "Empty Destination"), Required] public string EmptyDestination { get; set; } + [Display(Name = "Property Configuration"), Required] public Property.Models.Configuration? PropertyConfiguration { get; set; } + [Display(Name = "Selected Source"), Required] public string SelectedSource { get; set; } + + public Configuration() + { + CompareSource = string.Empty; + EmptyDestination = string.Empty; + SelectedSource = string.Empty; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/Not-Copy-Copy/Models/Configuration.cs b/Not-Copy-Copy/Models/Configuration.cs new file mode 100644 index 0000000..08816ae --- /dev/null +++ b/Not-Copy-Copy/Models/Configuration.cs @@ -0,0 +1,43 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Not.Copy.Copy.Models; + +public class Configuration +{ + + protected string _CompareSource; + protected string _EmptyDestination; + protected Property.Models.Configuration? _PropertyConfiguration; + protected string _SelectedSource; + public string CompareSource => _CompareSource; + public string EmptyDestination => _EmptyDestination; + public Property.Models.Configuration? PropertyConfiguration => _PropertyConfiguration; + public string SelectedSource => _SelectedSource; + + [JsonConstructor] + public Configuration(string compareSource, string emptyDestination, Property.Models.Configuration? propertyConfiguration, string selectedSource) + { + _CompareSource = compareSource; + _EmptyDestination = emptyDestination; + _PropertyConfiguration = propertyConfiguration; + _SelectedSource = selectedSource; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + + public void Set(Property.Models.Configuration propertyConfiguration) => _PropertyConfiguration = propertyConfiguration; + + public void Update() + { + _PropertyConfiguration?.Update(); + _CompareSource = Path.GetFullPath(_CompareSource); + _SelectedSource = Path.GetFullPath(_SelectedSource); + _EmptyDestination = Path.GetFullPath(_EmptyDestination); + } + +} \ No newline at end of file diff --git a/Not-Copy-Copy/Models/Stateless/AppSettings.cs b/Not-Copy-Copy/Models/Stateless/AppSettings.cs new file mode 100644 index 0000000..25e5179 --- /dev/null +++ b/Not-Copy-Copy/Models/Stateless/AppSettings.cs @@ -0,0 +1,40 @@ +using Microsoft.Extensions.Configuration; +using System.Text.Json; + +namespace View_by_Distance.Not.Copy.Copy.Models.Stateless; + +public abstract class AppSettings +{ + + public static Models.AppSettings Get(IConfigurationRoot configurationRoot) + { + Models.AppSettings? result; + Binder.AppSettings appSettings = configurationRoot.Get(); + string json = JsonSerializer.Serialize(appSettings, new JsonSerializerOptions() { WriteIndented = true }); + result = JsonSerializer.Deserialize(json); + if (result is null) + throw new Exception(json); + if (string.IsNullOrEmpty(result.Company)) + throw new Exception(json); + string jsonThis = result.ToString(); + if (jsonThis != json) + { + int? check = null; + int min = new int[] { json.Length, jsonThis.Length }.Min(); + for (int i = 0; i < min; i++) + { + if (json[i] == jsonThis[i]) + continue; + check = i; + break; + } + if (check is null) + throw new Exception(); + string a = json[..check.Value].Split(',')[^1]; + string b = json[check.Value..].Split(',')[0]; + throw new Exception($"{a}{b}"); + } + return result; + } + +} \ No newline at end of file diff --git a/Not-Copy-Copy/Models/Stateless/Configuration.cs b/Not-Copy-Copy/Models/Stateless/Configuration.cs new file mode 100644 index 0000000..c87ac8b --- /dev/null +++ b/Not-Copy-Copy/Models/Stateless/Configuration.cs @@ -0,0 +1,44 @@ +using Microsoft.Extensions.Configuration; +using Phares.Shared; +using System.Text.Json; + +namespace View_by_Distance.Not.Copy.Copy.Models.Stateless; + +public abstract class Configuration +{ + + public static Models.Configuration Get(IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, string workingDirectory, Property.Models.Configuration propertyConfiguration) + { + Models.Configuration? result; + string environmentName = IsEnvironment.GetEnvironmentName(isEnvironment); + string section = string.Concat(environmentName, ":", nameof(Binder.Configuration)); + IConfigurationSection configurationSection = configurationRoot.GetSection(section); + Binder.Configuration configuration = configurationSection.Get(); + string json = JsonSerializer.Serialize(configuration, new JsonSerializerOptions() { WriteIndented = true }); + result = JsonSerializer.Deserialize(json); + if (result is null) + throw new Exception(json); + string jsonThis = result.ToString(); + result.Set(propertyConfiguration); + result.Update(); + if (jsonThis != json) + { + int? check = null; + int min = new int[] { json.Length, jsonThis.Length }.Min(); + for (int i = 0; i < min; i++) + { + if (json[i] == jsonThis[i]) + continue; + check = i; + break; + } + if (check is null) + throw new Exception(); + string a = json[..check.Value].Split(',')[^1]; + string b = json[check.Value..].Split(',')[0]; + throw new Exception($"{a}{b}"); + } + return result; + } + +} \ No newline at end of file diff --git a/Not-Copy-Copy/Models/Stateless/SerilogExtensionMethods.cs b/Not-Copy-Copy/Models/Stateless/SerilogExtensionMethods.cs new file mode 100644 index 0000000..ae89478 --- /dev/null +++ b/Not-Copy-Copy/Models/Stateless/SerilogExtensionMethods.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Not.Copy.Copy.Models.Stateless; + +public static class SerilogExtensionMethods +{ + + internal static void Warn(this Serilog.ILogger log, string messageTemplate) => log.Warning(messageTemplate); + + internal static void Info(this Serilog.ILogger log, string messageTemplate) => log.Information(messageTemplate); + +} \ No newline at end of file diff --git a/Not-Copy-Copy/Not-Copy-Copy.cs b/Not-Copy-Copy/Not-Copy-Copy.cs new file mode 100644 index 0000000..dbd313e --- /dev/null +++ b/Not-Copy-Copy/Not-Copy-Copy.cs @@ -0,0 +1,193 @@ +using Microsoft.Extensions.Configuration; +using Phares.Shared; +using View_by_Distance.Not.Copy.Copy.Models; +using View_by_Distance.Property.Models; +using View_by_Distance.Shared.Models.Methods; + +namespace View_by_Distance.Not.Copy.Copy; + +public class NotCopyCopy +{ + + private readonly Serilog.ILogger? _Log; + private readonly AppSettings _AppSettings; + private readonly List _Exceptions; + private readonly IsEnvironment _IsEnvironment; + private readonly Models.Configuration _Configuration; + private readonly List> _FileKeyValuePairs; + private readonly Dictionary>> _FilePropertiesKeyValuePairs; + + public NotCopyCopy(List args, IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, AppSettings appSettings, string workingDirectory, bool isSilent, IConsole console) + { + if (isSilent) + { } + if (args is null) + { } + if (console is null) + { } + _AppSettings = appSettings; + if (appSettings.MaxDegreeOfParallelism is null) + throw new Exception($"{nameof(appSettings.MaxDegreeOfParallelism)} is null!"); + _IsEnvironment = isEnvironment; + _Exceptions = new List(); + _Log = Serilog.Log.ForContext(); + _FileKeyValuePairs = new List>(); + _FilePropertiesKeyValuePairs = new Dictionary>>(); + Property.Models.Configuration propertyConfiguration = Property.Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory); + Property.Models.Configuration.Verify(propertyConfiguration); + Models.Configuration configuration = Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory, propertyConfiguration); + Verify(configuration); + _Configuration = configuration; + if (propertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass is null) + throw new Exception($"{nameof(propertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass)} is null!"); + if (propertyConfiguration.PopulatePropertyId is null) + throw new Exception($"{nameof(propertyConfiguration.PopulatePropertyId)} is null!"); + if (!_IsEnvironment.Development) + throw new Exception("This program only allows development environments!"); + string searchPattern = "*"; + long ticks = DateTime.Now.Ticks; + List topDirectories = new(); + List compareSourceGroupCollection; + List selectedSourceGroupCollection; + PropertyLogic propertyLogic = GetPropertyLogic(); + List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> groupCollection; + groupCollection = Property.Models.Stateless.A_Property.GetGroupCollection(_Configuration.CompareSource, searchPattern, topDirectories, propertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass.Value, reverse: false); + if (appSettings.MaxDegreeOfParallelism.Value < 2) + ticks = LogDelta(ticks, nameof(Property.Models.Stateless.A_Property.GetGroupCollection)); + compareSourceGroupCollection = propertyLogic.GetParallelWork(propertyConfiguration, topDirectories, groupCollection, firstPass: true, filterOnFirstPass: true); + if (appSettings.MaxDegreeOfParallelism.Value < 2) + ticks = LogDelta(ticks, nameof(PropertyLogic.GetParallelWork)); + topDirectories.Clear(); + groupCollection = Property.Models.Stateless.A_Property.GetGroupCollection(configuration.SelectedSource, searchPattern, topDirectories, propertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass.Value, reverse: false); + if (appSettings.MaxDegreeOfParallelism.Value < 2) + ticks = LogDelta(ticks, nameof(Property.Models.Stateless.A_Property.GetGroupCollection)); + selectedSourceGroupCollection = propertyLogic.GetParallelWork(propertyConfiguration, topDirectories, groupCollection, firstPass: true, filterOnFirstPass: true); + if (appSettings.MaxDegreeOfParallelism.Value < 2) + ticks = LogDelta(ticks, nameof(PropertyLogic.GetParallelWork)); + string directoryName; + List distinct = new(); + List<(string Source, string[] Destination)> copyCollection = GetCopyCollection(compareSourceGroupCollection, selectedSourceGroupCollection); + foreach ((string source, string[] destination) in copyCollection) + { + directoryName = Path.Combine(destination.Take(destination.Length - 1).ToArray()); + if (distinct.Contains(directoryName)) + continue; + distinct.Add(directoryName); + if (!Directory.Exists(directoryName)) + _ = Directory.CreateDirectory(directoryName); + } + _Log.Information($"Ready to copy {copyCollection.Count} file(s)?"); + for (int y = 0; y < int.MaxValue; y++) + { + _Log.Information("Press \"Y\" key to to copy file(s)"); + if (Console.ReadKey().Key == ConsoleKey.Y) + break; + } + _Log.Information(". . ."); + int copied = 0; + string fullFileName; + foreach ((string source, string[] destination) in copyCollection) + { + if (copied % 500 == 0) + _Log.Information($"{copied})"); + fullFileName = Path.Combine(destination); + if (File.Exists(fullFileName)) + continue; + File.Copy(source, fullFileName); + copied += 1; + } + _Log.Information($"{copied} file(s) copied"); + for (int y = 0; y < int.MaxValue; y++) + { + _Log.Information("Press \"Y\" key to continue or close console"); + if (Console.ReadKey().Key == ConsoleKey.Y) + break; + } + _Log.Information(". . ."); + } + + private static void Verify(Models.Configuration configuration) + { + if (Path.GetPathRoot(configuration.SelectedSource) == configuration.SelectedSource) + throw new Exception($"{nameof(configuration.SelectedSource)} should have at least one level!"); + if (string.IsNullOrEmpty(configuration.CompareSource) || !Directory.Exists(configuration.CompareSource)) + throw new Exception($"{nameof(configuration.CompareSource)} must have a value and exits!"); + if (string.IsNullOrEmpty(configuration.EmptyDestination) || Directory.Exists(configuration.EmptyDestination)) + throw new Exception($"{nameof(configuration.EmptyDestination)} can't exit!"); + if (string.IsNullOrEmpty(configuration.SelectedSource) || !Directory.Exists(configuration.SelectedSource)) + throw new Exception($"{nameof(configuration.SelectedSource)} must have a value and exits!"); + if (configuration.SelectedSource.Length != configuration.CompareSource.Length) + throw new Exception($"{nameof(configuration.SelectedSource)} and {nameof(configuration.CompareSource)} must be the same length!"); + } + + private long LogDelta(long ticks, string methodName) + { + long result; + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + double delta = new TimeSpan(DateTime.Now.Ticks - ticks).TotalMilliseconds; + _Log.Debug($"{methodName} took {Math.Floor(delta)} millisecond(s)"); + result = DateTime.Now.Ticks; + return result; + } + + private PropertyLogic GetPropertyLogic() + { + PropertyLogic result; + + string[] verifyToSeason = Array.Empty(); + + if (_AppSettings.MaxDegreeOfParallelism is null) + throw new Exception($"{nameof(_AppSettings.MaxDegreeOfParallelism)} is null!"); + if (_Configuration?.PropertyConfiguration is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + result = new(_AppSettings.MaxDegreeOfParallelism.Value, _Configuration.PropertyConfiguration, verifyToSeason); + return result; + } + + private List<(string Source, string[] Destination)> GetCopyCollection(List compareSourceGroupCollection, List selectedSourceGroupCollection) + { + List<(string Source, string[] Destination)> results = new(); + string key; + string fileName; + A_Property? property; + string destinationDirectory; + List directoryNames; + List destinationCollection; + string filteredSourceDirectoryFile; + Dictionary keyValuePairs = new(); + foreach (Group group in compareSourceGroupCollection) + { + for (int i = 0; i < group.FilteredSourceDirectoryFiles.Length; i++) + { + property = group.PropertyCollection[i]; + if (property is null) + continue; + key = string.Concat(group.SourceDirectory[_Configuration.CompareSource.Length..], Path.GetFileName(group.FilteredSourceDirectoryFiles[i])); + keyValuePairs.Add(key, property); + } + } + foreach (Group group in selectedSourceGroupCollection) + { + for (int i = 0; i < group.FilteredSourceDirectoryFiles.Length; i++) + { + destinationCollection = new(); + property = group.PropertyCollection[i]; + if (property is null) + continue; + filteredSourceDirectoryFile = group.FilteredSourceDirectoryFiles[i]; + fileName = Path.GetFileName(filteredSourceDirectoryFile); + key = string.Concat(group.SourceDirectory[_Configuration.SelectedSource.Length..], fileName); + if (keyValuePairs.ContainsKey(key) && keyValuePairs[key].LastWriteTime == property.LastWriteTime) + continue; + destinationDirectory = string.Concat(_Configuration.EmptyDestination, group.SourceDirectory[_Configuration.SelectedSource.Length..]); + directoryNames = Property.Models.Stateless.IPath.GetDirectoryNames(destinationDirectory); + destinationCollection.AddRange(directoryNames); + destinationCollection.Add(fileName); + results.Add(new(filteredSourceDirectoryFile, destinationCollection.ToArray())); + } + } + return results; + } + +} \ No newline at end of file diff --git a/Not-Copy-Copy/Not-Copy-Copy.csproj b/Not-Copy-Copy/Not-Copy-Copy.csproj new file mode 100644 index 0000000..ebb0038 --- /dev/null +++ b/Not-Copy-Copy/Not-Copy-Copy.csproj @@ -0,0 +1,63 @@ + + + enable + 10.0 + enable + Exe + win-x64 + net6.0 + + + Phares.View.by.Distance.Not.Copy.Copy + false + 5.0.402.104 + Mike Phares + Phares + true + snupkg + + + true + true + true + + + Windows + + + OSX + + + Linux + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Always + + + \ No newline at end of file diff --git a/Not-Copy-Copy/Program.cs b/Not-Copy-Copy/Program.cs new file mode 100644 index 0000000..ab7f609 --- /dev/null +++ b/Not-Copy-Copy/Program.cs @@ -0,0 +1,127 @@ +using Microsoft.Extensions.Configuration; +using Phares.Shared; +using Serilog; +using System.Diagnostics; +using System.Reflection; +using View_by_Distance.Not.Copy.Copy.Models; +using View_by_Distance.Shared.Models.Stateless.Methods; + +namespace View_by_Distance.Not.Copy.Copy; + +public class Program +{ + + public static void Secondary(List args) + { + LoggerConfiguration loggerConfiguration = new(); + Assembly assembly = Assembly.GetExecutingAssembly(); + bool debuggerWasAttachedAtLineZero = Debugger.IsAttached || assembly.Location.Contains(@"\bin\Debug"); + IsEnvironment isEnvironment = new(processesCount: null, nullASPNetCoreEnvironmentIsDevelopment: debuggerWasAttachedAtLineZero, nullASPNetCoreEnvironmentIsProduction: !debuggerWasAttachedAtLineZero); + IConfigurationBuilder configurationBuilder = new ConfigurationBuilder() + .AddEnvironmentVariables() + .AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true); + IConfigurationRoot configurationRoot = configurationBuilder.Build(); + AppSettings appSettings = Models.Stateless.AppSettings.Get(configurationRoot); + if (appSettings.MaxDegreeOfParallelism is null) + throw new Exception("MaxDegreeOfParallelism must be set!"); + if (appSettings.MaxDegreeOfParallelism.Value > Environment.ProcessorCount) + throw new Exception("MaxDegreeOfParallelism must be =< Environment.ProcessorCount!"); + if (string.IsNullOrEmpty(appSettings.WorkingDirectoryName)) + throw new Exception("Working directory name must have a value!"); + string workingDirectory = IWorkingDirectory.GetWorkingDirectory(assembly.GetName().Name, appSettings.WorkingDirectoryName); + Environment.SetEnvironmentVariable(nameof(workingDirectory), workingDirectory); + _ = ConfigurationLoggerConfigurationExtensions.Configuration(loggerConfiguration.ReadFrom, configurationRoot); + Log.Logger = loggerConfiguration.CreateLogger(); + ILogger log = Log.ForContext(); + int silentIndex = args.IndexOf("s"); + if (silentIndex > -1) + args.RemoveAt(silentIndex); + try + { + if (args is null) + throw new Exception("args is null!"); +#nullable disable + if (Property.Models.Stateless.A_Property.IsWrongYear("-".Split(' '), "2021").Item1.HasValue) + throw new Exception("-"); + if (Property.Models.Stateless.A_Property.IsWrongYear("Christmass".Split(' '), "2021").Item1.HasValue) + throw new Exception("Christmass"); + if (Property.Models.Stateless.A_Property.IsWrongYear("Christmass 2021".Split(' '), "2021").Item1.Value) + throw new Exception("Christmass"); + if (Property.Models.Stateless.A_Property.IsWrongYear("Christmass ~2021".Split(' '), "2021").Item1.Value) + throw new Exception("Christmass"); + if (Property.Models.Stateless.A_Property.IsWrongYear("Christmass ~2021.4".Split(' '), "2021").Item1.Value) + throw new Exception("Christmass"); + if (!Property.Models.Stateless.A_Property.IsWrongYear("Christmass 2021".Split(' '), "2025").Item1.Value) + throw new Exception("Christmass"); + if (!Property.Models.Stateless.A_Property.IsWrongYear("Christmass ~2021".Split(' '), "2025").Item1.Value) + throw new Exception("Christmass"); + if (!Property.Models.Stateless.A_Property.IsWrongYear("Christmass ~2021.4".Split(' '), "2025").Item1.Value) + throw new Exception("Christmass"); + if (Property.Models.Stateless.A_Property.IsWrongYear("England 2017".Split(' '), "2017").Item1.Value) + throw new Exception("England"); + if (Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael".Split(' '), "2021").Item1.HasValue) + throw new Exception("Logan Michael"); + if (Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael 2021".Split(' '), "2021").Item1.Value) + throw new Exception("Logan Michael"); + if (Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael ~2021".Split(' '), "2021").Item1.Value) + throw new Exception("Logan Michael"); + if (Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael ~2021.4".Split(' '), "2021").Item1.Value) + throw new Exception("Logan Michael"); + if (!Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael 2021".Split(' '), "2025").Item1.Value) + throw new Exception("Logan Michael"); + if (!Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael ~2021".Split(' '), "2025").Item1.Value) + throw new Exception("Logan Michael"); + if (!Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael ~2021.4".Split(' '), "2025").Item1.Value) + throw new Exception("Logan Michael"); + if (Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael ~2021.4".Split(' '), "2021").Item2[0] != "~2021.4") + throw new Exception("Logan Michael"); + if (Property.Models.Stateless.A_Property.IsWrongYear("Chelsea's 2nd Birthday =2014".Split(' '), "2014").Item1.Value) + throw new Exception("Chelsea"); +#nullable restore + if (Property.Models.Stateless.IPath.GetDirectoryNames(@"C:\Tmp")[0] != @"C:\") + throw new Exception(); + if (Property.Models.Stateless.IPath.GetDirectoryNames(@"C:\Tmp")[1] != "Tmp") + throw new Exception(); + if (Property.Models.Stateless.IPath.GetDirectoryNames(@"C:\Tmp\mike.txt")[1] != "Tmp") + throw new Exception(); + if (Property.Models.Stateless.IPath.GetDirectoryNames(@"C:\Tmp\a.txt")[1] != "Tmp") + throw new Exception(); + if (Property.Models.Stateless.IPath.GetDirectoryNames(@"C:\Tmp\Mike\a.txt")[2] != "Mike") + throw new Exception(); + if (Property.Models.Stateless.IPath.GetDirectoryNames(@"I:\Images 2019-06-08 - 34a9240ac28b52da97428d7725153a80a757ee6b - II\=2010.2 Summer\Dsc_8558.jpg")[0] != @"I:\") + throw new Exception(); + if (Property.Models.Stateless.IPath.GetDirectoryNames(@"I:\Images 2019-06-08 - 34a9240ac28b52da97428d7725153a80a757ee6b - II\=2010.2 Summer\Dsc_8558.jpg")[1] != @"Images 2019-06-08 - 34a9240ac28b52da97428d7725153a80a757ee6b - II") + throw new Exception(); + if (Property.Models.Stateless.IPath.GetDirectoryNames(@"I:\Images 2019-06-08 - 34a9240ac28b52da97428d7725153a80a757ee6b - II\=2010.2 Summer\Dsc_8558.jpg")[2] != @"=2010.2 Summer") + throw new Exception(); + if (Property.Models.Stateless.IPath.GetDirectoryNames(@"I:\Images 2019-06-08 - 34a9240ac28b52da97428d7725153a80a757ee6b - II\=2010.2 Summer")[2] != @"=2010.2 Summer") + throw new Exception(); + Shared.Models.Console console = new(); + NotCopyCopy _ = new(args, isEnvironment, configurationRoot, appSettings, workingDirectory, silentIndex > -1, console); + } + catch (Exception ex) + { + log.Fatal(string.Concat(ex.Message, Environment.NewLine, ex.StackTrace)); + } + finally + { + Log.CloseAndFlush(); + } + if (silentIndex > -1) + log.Debug("Done. Bye"); + else + { + log.Debug("Done. Press 'Enter' to end"); + _ = Console.ReadLine(); + } + } + + public static void Main(string[] args) + { + if (args is not null) + Secondary(args.ToList()); + else + Secondary(new List()); + } + +} \ No newline at end of file diff --git a/Not-Copy-Copy/appsettings.Development.json b/Not-Copy-Copy/appsettings.Development.json new file mode 100644 index 0000000..7596b7e --- /dev/null +++ b/Not-Copy-Copy/appsettings.Development.json @@ -0,0 +1,339 @@ +{ + "Company": "Mike Phares", + "Linux": {}, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Log4netProvider": "Debug", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "MaxDegreeOfParallelism": 6, + "Serilog": { + "Using": [ + "Serilog.Sinks.Console", + "Serilog.Sinks.File" + ], + "MinimumLevel": "Debug", + "WriteTo": [ + { + "Name": "Debug", + "Args": { + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}" + } + }, + { + "Name": "Console", + "Args": { + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "%workingDirectory% - Log/log-.txt", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}", + "rollingInterval": "Hour" + } + } + ], + "Enrich": [ + "FromLogContext", + "WithMachineName", + "WithThreadId" + ], + "Properties": { + "Application": "Sample" + } + }, + "WorkingDirectoryName": "PharesApps", + "Windows": { + "Configuration": { + "DateGroup": "2022-04-07", + "FileNameDirectorySeparator": ".Z.", + "ForcePropertyLastWriteTimeToCreationTime": false, + "MaxImagesInDirectoryForTopLevelFirstPass": 50, + "Pattern": "[^ABCDEFGHIJKLMNOPQRSTUVWXYZbcdfghjklmnpqrstvwxyz0-9]", + "PopulatePropertyId": false, + "PropertiesChangedForProperty": false, + "CompareSource": "E:/Images 2021-10-29 - 34a9240ac28b52da97428d7725153a80a757ee6b - III", + "SelectedSource": "E:/Images 2018-05-12 - b01d4763d8853b6d6057a3870b2723449726da75 - III", + "EmptyDestination": "E:/. Not-Copy-Copy/Images 2018-05-12 - b01d4763d8853b6d6057a3870b2723449726da75 - Not-Copy-Copy", + "WriteBitmapDataBytes": false, + "IgnoreExtensions": [ + ".gif", + ".GIF" + ], + "PropertyContentCollectionFiles": [], + "ValidImageFormatExtensions": [ + ".bmp", + ".BMP", + ".gif", + ".GIF", + ".jpeg", + ".JPEG", + ".jpg", + ".JPG", + ".png", + ".PNG", + ".tiff", + ".TIFF" + ], + "ValidMetadataExtensions": [ + ".3gp", + ".3GP", + ".amr", + ".AMR", + ".avi", + ".AVI", + ".bmp", + ".BMP", + ".gif", + ".GIF", + ".ico", + ".ICO", + ".jpeg", + ".JPEG", + ".jpg", + ".JPG", + ".m4v", + ".M4V", + ".mov", + ".MOV", + ".mp4", + ".MP4", + ".mta", + ".MTA", + ".png", + ".PNG", + ".tiff", + ".TIFF" + ], + "VerifyToSeason": [ + ". 2000", + ". 2001", + ". 2002", + ". 2003", + ". 2004", + ". 2005", + ". 2006", + ". 2007", + ". 2008", + ". 2009", + ". 2010", + ". 2011", + ". 2012", + ". 2013", + ". 2014", + ". 2015", + ". 2016", + ". 2017", + ". 2018", + ". 2019", + ". 2020", + ". 2021", + ". 2022", + ". 2023", + ". 2024", + ". 2025", + ". 2026", + ". 2027", + ". 2028", + ". 2029", + "=2000.0 Winter", + "=2002.1 Spring", + "=2002.4 Winter", + "=2003.0 Winter", + "=2003.1 Spring", + "=2003.3 Fall", + "=2003.4 Winter", + "=2004.0 Winter", + "=2005.1 Spring", + "=2005.2 Summer", + "=2005.3 Fall", + "=2005.4 Winter", + "=2006.0 Winter", + "=2006.1 Spring", + "=2006.3 Fall", + "=2007.0 Winter", + "=2007.2 Summer Logan Michael", + "=2007.2 Summer", + "=2007.3 Fall Logan Michael", + "=2007.4 Winter Logan Michael", + "=2008.0 Winter Logan Michael", + "=2008.1 Spring Logan Michael", + "=2008.2 Summer Logan Michael", + "=2008.2 Summer", + "=2008.3 Fall Logan Michael", + "=2009.0 Winter Logan Michael", + "=2009.0 Winter", + "=2009.1 Spring Logan Michael", + "=2009.1 Spring", + "=2009.2 Summer Logan Michael", + "=2009.2 Summer", + "=2009.3 Fall Logan Michael", + "=2009.3 Fall", + "=2009.4 Winter Logan Michael", + "=2009.4 Winter", + "=2010.0 Winter Logan Michael", + "=2010.0 Winter", + "=2010.1 Spring Logan Michael", + "=2010.1 Spring", + "=2010.2 Summer", + "=2010.3 Fall Logan Michael", + "=2010.3 Fall", + "=2010.4 Winter", + "=2011.0 Winter", + "=2011.1 Spring", + "=2011.2 Summer", + "=2011.3 Fall", + "=2011.4 Winter", + "=2012.0 Winter Chelsea 2012", + "=2012.0 Winter Chelsea", + "=2012.0 Winter", + "=2012.1 Spring Chelsea", + "=2012.1 Spring", + "=2012.2 Summer Chelsea", + "=2012.2 Summer", + "=2012.3 Fall Chelsea", + "=2012.3 Fall", + "=2012.4 Winter Chelsea", + "=2012.4 Winter", + "=2013.0 Winter Chelsea 2013", + "=2013.0 Winter Chelsea", + "=2013.0 Winter", + "=2013.1 Spring", + "=2013.2 Summer Chelsea", + "=2013.2 Summer", + "=2013.3 Fall Chelsea", + "=2013.3 Fall", + "=2013.4 Winter", + "=2014.0 Winter", + "=2014.1 Spring", + "=2014.2 Summer", + "=2014.3 Fall", + "=2014.4 Winter", + "=2015.0 Winter", + "=2015.1 Spring", + "=2015.2 Summer", + "=2015.3 Fall", + "=2015.4 Winter", + "=2016.0 Winter", + "=2016.1 Spring", + "=2016.2 Summer", + "=2016.3 Fall", + "=2016.4 Winter", + "=2017.1 Spring", + "=2017.2 Summer", + "=2017.3 Fall", + "=2017.4 Winter", + "=2018.0 Winter", + "=2018.1 Spring", + "=2018.3 Fall", + "=2018.4 Winter", + "=2019.0 Winter", + "=2019.1 Spring", + "=2019.2 Summer", + "=2019.3 Fall", + "=2019.4 Winter", + "=2020.0 Winter", + "=2020.1 Spring", + "=2020.2 Summer", + "=2020.3 Fall", + "=2020.4 Winter", + "=2021.1 Spring", + "=2021.2 Summer", + "=2021.3 Fall", + "=2021.4 Winter", + "=2022.0 Winter", + "=2022.1 Spring", + "Anthem 2015", + "April 2010", + "April 2013", + "December 2006", + "December 2010", + "Fall 2005", + "Fall 2015", + "Fall 2016", + "Fall 2017", + "Fall 2018", + "Fall 2019", + "Fall 2020", + "Fall 2021", + "February 2010", + "January 2015", + "July 2010", + "June 2010", + "Kids 2005", + "March 2013", + "May 2010", + "May 2011", + "May 2013", + "October 2005", + "October 2014", + "Spring 2013", + "Spring 2014", + "Spring 2016", + "Spring 2018", + "Spring 2019", + "Spring 2020", + "Summer 2011", + "Summer 2012", + "Summer 2013", + "Summer 2014", + "Summer 2015", + "Summer 2016", + "Summer 2017", + "Summer 2018", + "Summer 2020", + "Summer 2021", + "Winter 2015", + "Winter 2016", + "Winter 2017", + "Winter 2018", + "Winter 2019-2020", + "Winter 2020", + "zzz =2005.0 Winter Tracy Pictures", + "zzz =2005.1 Spring Tracy Pictures", + "zzz =2005.2 Summer Tracy Pictures", + "zzz =2005.3 Fall Tracy Pictures", + "zzz =2005.4 Winter Tracy Pictures", + "zzz =2006.1 Spring Tracy Pictures", + "zzz =2007.0 Winter Tracy Pictures", + "zzz =2007.2 Summer Tracy Pictures", + "zzz =2008.0 Winter Tracy Pictures", + "zzz =2008.2 Summer Tracy Pictures", + "zzz =2009.0 Winter Tracy Pictures", + "zzz =2009.2 Summer Tracy Pictures", + "zzz =2009.3 Fall Tracy Pictures", + "zzz =2009.4 Winter Tracy Pictures", + "zzz =2010.0 Winter Tracy Pictures", + "zzz =2010.1 Spring Tracy Pictures", + "zzz =2010.2 Summer Tracy Pictures", + "zzz =2010.3 Fall Tracy Pictures", + "zzz =2011.0 Winter Tracy Pictures", + "zzz =2011.1 Spring Tracy Pictures", + "zzz =2011.2 Summer Tracy Pictures", + "zzz =2011.3 Fall Tracy Pictures", + "zzz =2011.4 Winter Tracy Pictures", + "zzz =2012.0 Winter Tracy Pictures", + "zzz =2012.1 Spring Tracy Pictures", + "zzz =2012.2 Summer Tracy Pictures", + "zzz =2012.3 Fall Tracy Pictures", + "zzz =2012.4 Winter Tracy Pictures", + "zzz =2013.0 Winter Tracy Pictures", + "zzz =2013.1 Spring Tracy Pictures", + "zzz =2013.2 Summer Tracy Pictures", + "zzz =2013.3 Fall Tracy Pictures", + "zzz =2013.4 Winter Tracy Pictures", + "zzz =2014.0 Winter Tracy Pictures", + "zzz =2014.1 Spring Tracy Pictures", + "zzz =2014.2 Summer Tracy Pictures", + "zzz =2014.3 Fall Tracy Pictures", + "zzz =2014.4 Winter Tracy Pictures", + "zzz =2015.0 Winter Tracy Pictures" + ] + } + } +} \ No newline at end of file diff --git a/PrepareForOld/.vscode/format-report.json b/PrepareForOld/.vscode/format-report.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/PrepareForOld/.vscode/format-report.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/PrepareForOld/.vscode/launch.json b/PrepareForOld/.vscode/launch.json new file mode 100644 index 0000000..7043023 --- /dev/null +++ b/PrepareForOld/.vscode/launch.json @@ -0,0 +1,30 @@ +{ + "version": "0.2.0", + "configurations": [ + { + // Use IntelliSense to find out which attributes exist for C# debugging + // Use hover for the description of the existing attributes + // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md + "name": ".NET Core Launch (console)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + // If you have changed target frameworks, make sure to update the program path. + "program": "${workspaceFolder}/bin/Debug/net6.0/win-x64/PrepareForOld.dll", + "args": [], + "env": { + "ASPNETCORE_ENVIRONMENT": "Development", + }, + "cwd": "${workspaceFolder}", + // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console + "console": "externalTerminal", + "stopAtEntry": false + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach", + "processName": "PrepareForOld" + } + ] +} \ No newline at end of file diff --git a/PrepareForOld/.vscode/settings.json b/PrepareForOld/.vscode/settings.json new file mode 100644 index 0000000..768342e --- /dev/null +++ b/PrepareForOld/.vscode/settings.json @@ -0,0 +1,14 @@ +{ + "cSpell.words": [ + "Barrick", + "bcdfghjklmnpqrstvwxyz", + "Beichler", + "Bohdi", + "Dlib", + "exif", + "nosj", + "Phares", + "Serilog", + "Vericruz" + ] +} \ No newline at end of file diff --git a/PrepareForOld/.vscode/tasks.json b/PrepareForOld/.vscode/tasks.json new file mode 100644 index 0000000..40c2d54 --- /dev/null +++ b/PrepareForOld/.vscode/tasks.json @@ -0,0 +1,42 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/PrepareForOld.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "publish", + "command": "dotnet", + "type": "process", + "args": [ + "publish", + "${workspaceFolder}/PrepareForOld.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "watch", + "command": "dotnet", + "type": "process", + "args": [ + "watch", + "run", + "${workspaceFolder}/PrepareForOld.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/PrepareForOld/Models/AppSettings.cs b/PrepareForOld/Models/AppSettings.cs new file mode 100644 index 0000000..138819c --- /dev/null +++ b/PrepareForOld/Models/AppSettings.cs @@ -0,0 +1,35 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.PrepareForOld.Models; + +public class AppSettings +{ + + protected string _Company; + protected string _WorkingDirectoryName; + protected int? _MaxDegreeOfParallelism; + public string Company => _Company; + public string WorkingDirectoryName => _WorkingDirectoryName; + public int? MaxDegreeOfParallelism => _MaxDegreeOfParallelism; + + // public AppSettings() + // { + + // } + + [JsonConstructor] + public AppSettings(string company, string workingDirectoryName, int? maxDegreeOfParallelism) + { + _Company = company; + _WorkingDirectoryName = workingDirectoryName; + _MaxDegreeOfParallelism = maxDegreeOfParallelism; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/PrepareForOld/Models/Binder/AppSettings.cs b/PrepareForOld/Models/Binder/AppSettings.cs new file mode 100644 index 0000000..5426197 --- /dev/null +++ b/PrepareForOld/Models/Binder/AppSettings.cs @@ -0,0 +1,26 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.Json; + +namespace View_by_Distance.PrepareForOld.Models.Binder; + +public class AppSettings +{ + + [Display(Name = "Company"), Required] public string Company { get; set; } + [Display(Name = "Working Directory Name"), Required] public string WorkingDirectoryName { get; set; } + [Display(Name = "Max Degree Of Parallelism"), Required] public int? MaxDegreeOfParallelism { get; set; } + + public AppSettings() + { + Company = string.Empty; + WorkingDirectoryName = string.Empty; + MaxDegreeOfParallelism = -1; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/PrepareForOld/Models/Binder/Configuration.cs b/PrepareForOld/Models/Binder/Configuration.cs new file mode 100644 index 0000000..8bfda5f --- /dev/null +++ b/PrepareForOld/Models/Binder/Configuration.cs @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.Json; + +namespace View_by_Distance.PrepareForOld.Models.Binder; + +public class Configuration +{ + + [Display(Name = "Property Configuration"), Required] public Property.Models.Configuration? PropertyConfiguration { get; set; } + [Display(Name = "Spelling"), Required] public string[] Spelling { get; set; } + + public Configuration() => Spelling = Array.Empty(); + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/PrepareForOld/Models/Configuration.cs b/PrepareForOld/Models/Configuration.cs new file mode 100644 index 0000000..208d9d9 --- /dev/null +++ b/PrepareForOld/Models/Configuration.cs @@ -0,0 +1,31 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.PrepareForOld.Models; + +public class Configuration +{ + + protected Property.Models.Configuration? _PropertyConfiguration; + protected readonly string[] _Spelling; + public Property.Models.Configuration? PropertyConfiguration => _PropertyConfiguration; + public string[] Spelling => _Spelling; + + [JsonConstructor] + public Configuration(Property.Models.Configuration? propertyConfiguration, string[] spelling) + { + _PropertyConfiguration = propertyConfiguration; + _Spelling = spelling; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + + public void Set(Property.Models.Configuration propertyConfiguration) => _PropertyConfiguration = propertyConfiguration; + + public void Update() => _PropertyConfiguration?.Update(); + +} \ No newline at end of file diff --git a/PrepareForOld/Models/SaveTabSeparatedValues/ImageExifInfo.cs b/PrepareForOld/Models/SaveTabSeparatedValues/ImageExifInfo.cs new file mode 100644 index 0000000..b00ebcd --- /dev/null +++ b/PrepareForOld/Models/SaveTabSeparatedValues/ImageExifInfo.cs @@ -0,0 +1,17 @@ +namespace View_by_Distance.PrepareForOld.Models.SaveTabSeparatedValues; + +public class ImageExifInfo +{ + public int Index { get; set; } + public DateTime CreationTime { get; set; } + public DateTime LastWriteTime { get; set; } + public DateTime? DateTime { get; set; } + public DateTime? DateTimeDigitized { get; set; } + public DateTime? DateTimeOriginal { get; set; } + public DateTime? GPSDateStamp { get; set; } + public string? Make { get; set; } + public string? Model { get; set; } + public string? Orientation { get; set; } + public int Width { get; set; } + public int Height { get; set; } +} \ No newline at end of file diff --git a/PrepareForOld/Models/SaveTabSeparatedValues/IndexInfo.cs b/PrepareForOld/Models/SaveTabSeparatedValues/IndexInfo.cs new file mode 100644 index 0000000..8d48e7a --- /dev/null +++ b/PrepareForOld/Models/SaveTabSeparatedValues/IndexInfo.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.PrepareForOld.Models.SaveTabSeparatedValues; + +public class IndexInfo +{ + public int Index { get; set; } + public string[]? FileSegmentCollection { get; set; } + public DateTime DateTime { get; set; } +} \ No newline at end of file diff --git a/PrepareForOld/Models/Stateless/AppSettings.cs b/PrepareForOld/Models/Stateless/AppSettings.cs new file mode 100644 index 0000000..667b5b7 --- /dev/null +++ b/PrepareForOld/Models/Stateless/AppSettings.cs @@ -0,0 +1,40 @@ +using Microsoft.Extensions.Configuration; +using System.Text.Json; + +namespace View_by_Distance.PrepareForOld.Models.Stateless; + +public abstract class AppSettings +{ + + public static Models.AppSettings Get(IConfigurationRoot configurationRoot) + { + Models.AppSettings? result; + Binder.AppSettings appSettings = configurationRoot.Get(); + string json = JsonSerializer.Serialize(appSettings, new JsonSerializerOptions() { WriteIndented = true }); + result = JsonSerializer.Deserialize(json); + if (result is null) + throw new Exception(json); + if (string.IsNullOrEmpty(result.Company)) + throw new Exception(json); + string jsonThis = result.ToString(); + if (jsonThis != json) + { + int? check = null; + int min = new int[] { json.Length, jsonThis.Length }.Min(); + for (int i = 0; i < min; i++) + { + if (json[i] == jsonThis[i]) + continue; + check = i; + break; + } + if (check is null) + throw new Exception(); + string a = json[..check.Value].Split(',')[^1]; + string b = json[check.Value..].Split(',')[0]; + throw new Exception($"{a}{b}"); + } + return result; + } + +} \ No newline at end of file diff --git a/PrepareForOld/Models/Stateless/Configuration.cs b/PrepareForOld/Models/Stateless/Configuration.cs new file mode 100644 index 0000000..2646d6c --- /dev/null +++ b/PrepareForOld/Models/Stateless/Configuration.cs @@ -0,0 +1,44 @@ +using Microsoft.Extensions.Configuration; +using Phares.Shared; +using System.Text.Json; + +namespace View_by_Distance.PrepareForOld.Models.Stateless; + +public abstract class Configuration +{ + + public static Models.Configuration Get(IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, string workingDirectory, Property.Models.Configuration propertyConfiguration) + { + Models.Configuration? result; + string environmentName = IsEnvironment.GetEnvironmentName(isEnvironment); + string section = string.Concat(environmentName, ":", nameof(Binder.Configuration)); + IConfigurationSection configurationSection = configurationRoot.GetSection(section); + Binder.Configuration configuration = configurationSection.Get(); + string json = JsonSerializer.Serialize(configuration, new JsonSerializerOptions() { WriteIndented = true }); + result = JsonSerializer.Deserialize(json); + if (result is null) + throw new Exception(json); + string jsonThis = result.ToString(); + result.Set(propertyConfiguration); + result.Update(); + if (jsonThis != json) + { + int? check = null; + int min = new int[] { json.Length, jsonThis.Length }.Min(); + for (int i = 0; i < min; i++) + { + if (json[i] == jsonThis[i]) + continue; + check = i; + break; + } + if (check is null) + throw new Exception(); + string a = json[..check.Value].Split(',')[^1]; + string b = json[check.Value..].Split(',')[0]; + throw new Exception($"{a}{b}"); + } + return result; + } + +} \ No newline at end of file diff --git a/PrepareForOld/Models/Stateless/SerilogExtensionMethods.cs b/PrepareForOld/Models/Stateless/SerilogExtensionMethods.cs new file mode 100644 index 0000000..29639e5 --- /dev/null +++ b/PrepareForOld/Models/Stateless/SerilogExtensionMethods.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.PrepareForOld.Models.Stateless; + +public static class SerilogExtensionMethods +{ + + internal static void Warn(this Serilog.ILogger log, string messageTemplate) => log.Warning(messageTemplate); + + internal static void Info(this Serilog.ILogger log, string messageTemplate) => log.Information(messageTemplate); + +} \ No newline at end of file diff --git a/PrepareForOld/PrepareForOld.cs b/PrepareForOld/PrepareForOld.cs new file mode 100644 index 0000000..20244bf --- /dev/null +++ b/PrepareForOld/PrepareForOld.cs @@ -0,0 +1,666 @@ +using Microsoft.Extensions.Configuration; +using Phares.Shared; +using System.Text.Json; +using System.Text.RegularExpressions; +using View_by_Distance.PrepareForOld.Models; +using View_by_Distance.Property.Models; +using View_by_Distance.Shared.Models.Methods; + +namespace View_by_Distance.PrepareForOld; + +public class PrepareForOld +{ + + private readonly Serilog.ILogger? _Log; + private readonly AppSettings _AppSettings; + private readonly List _Exceptions; + private readonly IsEnvironment _IsEnvironment; + private readonly Models.Configuration _Configuration; + private readonly List> _FileKeyValuePairs; + private readonly List<(string Find, string Replace)> _SpellingFindReplace; + private readonly Dictionary>> _FilePropertiesKeyValuePairs; + + public PrepareForOld(List args, IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, AppSettings appSettings, string workingDirectory, bool isSilent, IConsole console) + { + if (isSilent) + { } + if (console is null) + { } + string spellingA; + string spellingB; + _AppSettings = appSettings; + if (appSettings.MaxDegreeOfParallelism is null) + throw new Exception($"{nameof(appSettings.MaxDegreeOfParallelism)} is null!"); + _SpellingFindReplace = new(); + _IsEnvironment = isEnvironment; + _Exceptions = new List(); + _Log = Serilog.Log.ForContext(); + _FileKeyValuePairs = new List>(); + _FilePropertiesKeyValuePairs = new Dictionary>>(); + Property.Models.Configuration propertyConfiguration = Property.Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory); + Property.Models.Configuration.Verify(propertyConfiguration); + Models.Configuration configuration = Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory, propertyConfiguration); + Verify(configuration); + if (propertyConfiguration.IgnoreExtensions is null) + throw new Exception($"{nameof(propertyConfiguration.IgnoreExtensions)} is null!"); + if (propertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass is null) + throw new Exception($"{nameof(propertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass)} is null!"); + for (int i = 0; i < configuration.Spelling.Length; i++) + { + spellingA = configuration.Spelling[i]; + spellingB = configuration.Spelling[i + 1]; + if (spellingB.Contains(spellingA)) + throw new Exception("Change configuration!"); + _SpellingFindReplace.Add(new(spellingA, spellingB)); + i += 1; + } + string[] dbFiles = Directory.GetFiles(propertyConfiguration.RootDirectory, "*.db", SearchOption.AllDirectories); + foreach (string dbFile in dbFiles) + File.Delete(dbFile); + string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(propertyConfiguration, nameof(A_Property), "{}"); + if (!Directory.Exists(aPropertySingletonDirectory)) + throw new Exception(aPropertySingletonDirectory); + ConsoleKey? consoleKey = null; + for (int y = 0; y < int.MaxValue; y++) + { + _Log.Information($"Execute {nameof(VerifyAgainstIndexInfoJsonFiles)} \"Y(es)\" or \"N(o)\"?"); + consoleKey = Console.ReadKey().Key; + if (consoleKey is ConsoleKey.Y or ConsoleKey.N) + break; + } + _Log.Information(". . ."); + if (consoleKey == ConsoleKey.Y) + VerifyAgainstIndexInfoJsonFiles(propertyConfiguration, aPropertySingletonDirectory); + for (int y = 0; y < int.MaxValue; y++) + { + _Log.Information($"Execute {nameof(SaveTabSeparatedValues)} \"Y(es)\" or \"N(o)\"?"); + consoleKey = Console.ReadKey().Key; + if (consoleKey is ConsoleKey.Y or ConsoleKey.N) + break; + } + _Log.Information(". . ."); + if (consoleKey == ConsoleKey.Y) + SaveTabSeparatedValues(propertyConfiguration, aPropertySingletonDirectory); + for (int y = 0; y < int.MaxValue; y++) + { + _Log.Information($"Execute {nameof(ReSaveJsonFiles)} \"Y(es)\" or \"N(o)\"?"); + consoleKey = Console.ReadKey().Key; + if (consoleKey is ConsoleKey.Y or ConsoleKey.N) + break; + } + _Log.Information(". . ."); + if (consoleKey == ConsoleKey.Y) + ReSaveJsonFiles(); + for (int y = 0; y < int.MaxValue; y++) + { + _Log.Information($"Execute {nameof(CopyMissingImagesLogs)} \"Y(es)\" or \"N(o)\"?"); + consoleKey = Console.ReadKey().Key; + if (consoleKey is ConsoleKey.Y or ConsoleKey.N) + break; + } + _Log.Information(". . ."); + if (consoleKey == ConsoleKey.Y) + CopyMissingImagesLogs(); + string message = $"There were {_Exceptions.Count} exception(s) thrown! {Environment.NewLine}{string.Join(Environment.NewLine, _Exceptions)}"; + _Log.Information(message); + if (_Exceptions.Count != 0) + throw new Exception(message); + _Configuration = configuration; + } + + private static void Verify(Models.Configuration configuration) + { + if (configuration.Spelling is null || !configuration.Spelling.Any()) + throw new Exception($"{nameof(configuration.Spelling)} should have at least one!"); + } + + private static List GetExifCollection(string infoDirectory, string infoDirectoryExtra, bool checkDistinct) + { + List results = new(); + string json; + Models.SaveTabSeparatedValues.ImageExifInfo[]? exifCollection; + List exifInfoFiles = Directory.GetFiles(infoDirectory, "ImageExifInfo.json", SearchOption.AllDirectories).ToList(); + if (!string.IsNullOrEmpty(infoDirectoryExtra)) + exifInfoFiles.AddRange(Directory.GetFiles(infoDirectoryExtra, "ImageExifInfo.json", SearchOption.AllDirectories)); + foreach (string exifInfoFile in exifInfoFiles) + { + json = File.ReadAllText(exifInfoFile); + exifCollection = JsonSerializer.Deserialize(json); + if (exifCollection is null) + continue; + results.AddRange(exifCollection); + } + if (checkDistinct) + { + int[] check = (from l in results select l.Index).Distinct().ToArray(); + if (check.Length != results.Count) + throw new Exception(); + } + return results; + } + + private List<(int Index, long Ticks, string RelativeDirectory, string FileNameWithoutExtension, string Extension, string RegexResult)> GetIndexCollection(string infoDirectory, string infoDirectoryExtra, bool checkDistinct) + { + List<(int Index, long Ticks, string RelativeDirectory, string FileNameWithoutExtension, string Extension, string RegexResult)> results = new(); + if (_Configuration?.PropertyConfiguration is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + long ticks; + string json; + string extension; + string corrected; + string regexResult; + string relativeDirectory; + List dateTimes; + string fileNameWithoutExtension; + string firstFileSegmentCollection; + Dictionary keyValuePairs = new(); + Models.SaveTabSeparatedValues.IndexInfo[]? indexCollection; + List exifCollection = GetExifCollection(infoDirectory, infoDirectoryExtra, checkDistinct); + List indexInfoFiles = Directory.GetFiles(infoDirectory, "IndexInfo.json", SearchOption.AllDirectories).ToList(); + if (!string.IsNullOrEmpty(infoDirectoryExtra)) + indexInfoFiles.AddRange(Directory.GetFiles(infoDirectoryExtra, "IndexInfo.json", SearchOption.AllDirectories)); + foreach (Models.SaveTabSeparatedValues.ImageExifInfo exifInfo in exifCollection) + { + dateTimes = Property.Models.Stateless.A_Property.GetDateTimes(exifInfo.CreationTime, exifInfo.LastWriteTime, exifInfo.DateTime, exifInfo.DateTimeDigitized, exifInfo.DateTimeOriginal, exifInfo.GPSDateStamp); + if (!checkDistinct && keyValuePairs.ContainsKey(exifInfo.Index)) + continue; + keyValuePairs.Add(exifInfo.Index, dateTimes.Min().Ticks); + } + foreach (string indexInfoFile in indexInfoFiles) + { + json = File.ReadAllText(indexInfoFile); + indexCollection = JsonSerializer.Deserialize(json); + if (indexCollection is null) + continue; + foreach (Models.SaveTabSeparatedValues.IndexInfo indexInfo in indexCollection) + { + if (indexInfo.FileSegmentCollection is null) + continue; + // if (indexInfo.FileSegmentCollection.Length != 1) + // continue; + ticks = keyValuePairs[indexInfo.Index]; + firstFileSegmentCollection = indexInfo.FileSegmentCollection[0]; + extension = Path.GetExtension(firstFileSegmentCollection); + fileNameWithoutExtension = Path.GetFileNameWithoutExtension(firstFileSegmentCollection); + corrected = firstFileSegmentCollection[..(firstFileSegmentCollection.Length - extension.Length)]; + relativeDirectory = firstFileSegmentCollection[..(firstFileSegmentCollection.Length - fileNameWithoutExtension.Length - extension.Length)]; + if ((from l in _SpellingFindReplace where corrected.Contains(l.Find) select true).Any()) + { + foreach ((string find, string replace) in _SpellingFindReplace) + corrected = corrected.Replace(find, replace); + } + if (string.IsNullOrEmpty(_Configuration.PropertyConfiguration.Pattern)) + regexResult = corrected; + else + regexResult = Regex.Replace(corrected, _Configuration.PropertyConfiguration.Pattern, string.Empty); + results.Add(new(indexInfo.Index, ticks, relativeDirectory, fileNameWithoutExtension, extension, regexResult)); + } + } + return results; + } + + private static List GetUseTabSeparatedValueIndices(string useDirectory) + { + List results = new(); + string[] lines; + string[] segments; + string[] tabSeparatedValueFiles = Directory.GetFiles(useDirectory, "*.tsv", SearchOption.TopDirectoryOnly); + foreach (string tabSeparatedValueFile in tabSeparatedValueFiles) + { + lines = File.ReadAllLines(tabSeparatedValueFile); + foreach (string line in lines) + { + if (string.IsNullOrEmpty(line)) + continue; + segments = line.Split('\t'); + if (segments.Length < 1) + continue; + if (!int.TryParse(segments[0], out int index)) + continue; + results.Add(index); + } + } + return results.Distinct().OrderBy(l => l).ToList(); + } + + private void SaveTabSeparatedValues(Property.Models.Configuration configuration, string aPropertySingletonDirectory) + { + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + if (_AppSettings.MaxDegreeOfParallelism is null) + throw new Exception($"{nameof(_AppSettings.MaxDegreeOfParallelism)} is null!"); + if (_Configuration?.PropertyConfiguration is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + string? rootDirectoryParent = Path.GetDirectoryName(_Configuration.PropertyConfiguration.RootDirectory); + if (string.IsNullOrEmpty(rootDirectoryParent)) + throw new Exception($"{nameof(rootDirectoryParent)} is null!"); + int z = 0; + int mappedIndex; + int? propertyId; + long? propertyTicks; + int loadLessThan = 7; + string useDirectory = Path.Combine(rootDirectoryParent, "Use - =="); + if (!Directory.Exists(useDirectory)) + _ = Directory.CreateDirectory(useDirectory); + string tempDirectory = Path.Combine(rootDirectoryParent, "Tmp"); + if (!Directory.Exists(tempDirectory)) + _ = Directory.CreateDirectory(tempDirectory); + string diffRootDirectory = string.Empty; + List duplicates = new(); + string imageSharedDirectory = Path.Combine(rootDirectoryParent, "Images - Shared"); + string namedFaceInfoFile = Path.Combine(imageSharedDirectory, "NamedFaceInfo.json"); + string infoDirectory = Path.Combine(imageSharedDirectory, "Images - 4) Info", "2020-06-07"); + string infoDirectoryExtra = Path.Combine(imageSharedDirectory, "Images - 4) Info - - - Extra", "2022-04-14"); + List mappedIndices = GetUseTabSeparatedValueIndices(useDirectory); + List<(int Index, string RelativeDirectory, string FileName, string RegexResult, long Ticks, int? PropertyId, long? PropertyTicks)> collection = new(); + PropertyCompare.Models.PropertyCompareLogic propertyCompareLogic = new(_AppSettings.MaxDegreeOfParallelism.Value, _Configuration.PropertyConfiguration, _SpellingFindReplace, diffRootDirectory); + PropertyCompare.Models.PropertyCompare[] propertyCompareCollection = propertyCompareLogic.Get(aPropertySingletonDirectory, loadLessThan, duplicates, deleteExtension: false); + { + long ticks = DateTime.Now.Ticks; + string[] lines = (from l in propertyCompareCollection select l.GetSelect()).ToArray(); + string aPropertyCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "[{}]"); + File.WriteAllLines(Path.Join(aPropertyCollectionDirectory, $". . . Ids - {ticks}.txt"), lines); + string json = JsonSerializer.Serialize(propertyCompareCollection, new JsonSerializerOptions { WriteIndented = true }); + File.WriteAllText(Path.Join(aPropertyCollectionDirectory, $". . . Ids - {ticks}.nosj"), json); + } + List<(int Index, long Ticks, string RelativeDirectory, string FileNameWithoutExtension, string Extension, string RegexResult)> indexCollection = GetIndexCollection(infoDirectory, infoDirectoryExtra, checkDistinct: true); + foreach ((int index, long ticks, string relativeDirectory, string fileNameWithoutExtension, string extension, string regexResult) in indexCollection) + { + z += 1; + if (_IsEnvironment.Development && z % 1000 == 0) + _Log.Debug($"{z}) Loop {_Configuration.PropertyConfiguration.RootDirectory}"); + propertyId = null; + propertyTicks = null; + foreach (PropertyCompare.Models.PropertyCompare propertyCompare in propertyCompareCollection) + { + if (propertyCompare?.Property?.Id is null) + continue; + if (ticks != propertyCompare.MinimumDateTime.Ticks) + { + // if (ticks > propertyCompare.MinimumDateTime.AddHours(18).Ticks || ticks < propertyCompare.MinimumDateTime.AddHours(-18).Ticks) + continue; + } + if (!regexResult.Equals(propertyCompare.RegexResult, StringComparison.CurrentCultureIgnoreCase)) + continue; + propertyId = propertyCompare.Property.Id; + propertyTicks = propertyCompare.MinimumDateTime.Ticks; + mappedIndex = mappedIndices.IndexOf(index); + if (mappedIndex > -1) + mappedIndices.RemoveAt(mappedIndex); + break; + } + collection.Add(new(index, relativeDirectory, $"{fileNameWithoutExtension}{extension}", regexResult, ticks, propertyId, propertyTicks)); + } + (int Index, string RelativeDirectory, string FileName, string RegexResult, long Ticks, int? PropertyId, long? PropertyTicks)[] matched = (from l in collection where l.PropertyId.HasValue select l).ToArray(); + (int Index, string RelativeDirectory, string FileName, string RegexResult, long Ticks, int? PropertyId, long? PropertyTicks)[] notMatched = (from l in collection where l.PropertyId is null select l).ToArray(); + string[] duplicatesLines = ( + from l + in duplicates + select $"{l.Property.Id}\t{l.RegexResult}\t{l.MinimumDateTime:yyyy-MM-dd_HH-mm-ss}\t{l.MinimumDateTime}\t{l.RelativeDirectory}\t{l.FileNameWithoutExtension}{l.Extension}.___" + ).ToArray(); + string[] matchedLines = ( + from l + in matched + select $"{l.Index}\t{l.PropertyId}\t{l.RegexResult}\t{new DateTime(l.Ticks):yyyy-MM-dd_HH-mm-ss}\t{l.PropertyTicks}\t{l.RelativeDirectory}\t{l.FileName}" + ).ToArray(); + List notMatchedLines = ( + from l + in notMatched + where !mappedIndices.Contains(l.Index) + select $"{l.Index}\t______________\t{l.RegexResult}\t{new DateTime(l.Ticks):yyyy-MM-dd_HH-mm-ss}\t_________________\t{l.RelativeDirectory}\t{l.FileName}" + ).ToList(); + { + long ticks = DateTime.Now.Ticks; + notMatchedLines.AddRange(from l in mappedIndices select $"{l}\tFrom other files"); + File.WriteAllLines($"{tempDirectory}/{collection.Count}-{ticks}.tsv", matchedLines); + File.WriteAllLines($"{tempDirectory}/{collection.Count}-{ticks}.txt", duplicatesLines); + File.WriteAllLines($"{tempDirectory}/{collection.Count}-{ticks}-Not.tsv", notMatchedLines); + } + _Log.Debug($"Done with {nameof(SaveTabSeparatedValues)}"); + } + + private static void GetUseTabSeparatedValueLines(string useDirectory, Dictionary> mappedLines) + { + string[] lines; + string[] segments; + string useDirectoryName = Path.GetFileName(useDirectory).Split('-')[1].Trim(); + string[] tabSeparatedValueFiles = Directory.GetFiles(useDirectory, "*.tsv", SearchOption.TopDirectoryOnly); + foreach (string tabSeparatedValueFile in tabSeparatedValueFiles) + { + lines = File.ReadAllLines(tabSeparatedValueFile); + foreach (string line in lines) + { + if (string.IsNullOrEmpty(line)) + continue; + segments = line.Split('\t'); + if (segments.Length < 1) + continue; + if (!int.TryParse(segments[0], out int index)) + continue; + if (!mappedLines.ContainsKey(index)) + mappedLines.Add(index, new()); + mappedLines[index].Add($"{line},\t{useDirectoryName}"); + } + } + } + + private static void Populate(Dictionary> keyValuePairs, Dictionary> mappedLines) + { + string[] segments; + foreach (KeyValuePair> keyValuePair in mappedLines) + { + segments = keyValuePair.Value[0].Split('\t'); + if (segments.Length < 2) + continue; + if (!int.TryParse(segments[1], out int id)) + continue; + if (!keyValuePairs.ContainsKey(id)) + keyValuePairs.Add(id, new() { id }); + keyValuePairs[id].Add(keyValuePair.Key); + } + } + + private static Dictionary GetUseTabSeparatedValue(string useEqualsDirectory, string use18HoursDirectory, string useAnyDateDirectory, Dictionary> keyValuePairs, List lines) + { + Dictionary results = new(); + string[] segments; + Dictionary> mappedLines = new(); + GetUseTabSeparatedValueLines(useEqualsDirectory, mappedLines); + GetUseTabSeparatedValueLines(use18HoursDirectory, mappedLines); + GetUseTabSeparatedValueLines(useAnyDateDirectory, mappedLines); + Populate(keyValuePairs, mappedLines); + foreach (KeyValuePair> keyValuePair in mappedLines) + { + segments = keyValuePair.Value[0].Split('\t'); + if (segments.Length < 2) + continue; + if (!int.TryParse(segments[1], out int id)) + continue; + foreach (string line in keyValuePair.Value) + lines.Add(line); + results.Add(keyValuePair.Key, id); + } + return results; + } + + private static void ReSaveExifFiles(string infoDirectory, string infoDirectoryIgnore, Dictionary findReplace, List missingIndices) + { + string json; + int propertyId; + Models.SaveTabSeparatedValues.ImageExifInfo[]? exifCollection; + List exifInfoFiles = Directory.GetFiles(infoDirectory, "ImageExifInfo.json", SearchOption.AllDirectories).ToList(); + exifInfoFiles.AddRange(Directory.GetFiles(infoDirectoryIgnore, "ImageExifInfo.json", SearchOption.AllDirectories)); + foreach (string exifInfoFile in exifInfoFiles) + { + json = File.ReadAllText(exifInfoFile); + exifCollection = JsonSerializer.Deserialize(json); + if (exifCollection is null) + continue; + foreach (Models.SaveTabSeparatedValues.ImageExifInfo exifInfo in exifCollection) + { + if (missingIndices.Contains(exifInfo.Index)) + continue; + propertyId = findReplace[exifInfo.Index]; + exifInfo.Index = propertyId; + } + json = JsonSerializer.Serialize(exifCollection); + File.WriteAllText(exifInfoFile, json); + } + } + + private static void ReSaveNamedFaceInfoFile(string namedFaceInfoFile, Dictionary findReplace, List missingIndices) + { + Dictionary destination = new(); + string json = File.ReadAllText(namedFaceInfoFile); + List<(int PropertyId, string[] Birthdays)> collection = new(); + JsonSerializerOptions jsonSerializerOptions = new() { WriteIndented = true }; + Dictionary? source = JsonSerializer.Deserialize>(json); + if (source is null) + throw new Exception($"{nameof(source)} is null!"); + { + int propertyId; + foreach (KeyValuePair keyValuePair in source) + { + if (missingIndices.Contains(keyValuePair.Key)) + continue; + propertyId = findReplace[keyValuePair.Key]; + collection.Add(new(propertyId, keyValuePair.Value)); + } + } + foreach ((int propertyId, string[] birthdays) in collection.OrderBy(l => l.PropertyId)) + { + if (destination.ContainsKey(propertyId)) + { + if (birthdays.Length != destination[propertyId].Length) + throw new Exception($"{birthdays.Length} != {destination[propertyId].Length}"); + if (birthdays[0] != destination[propertyId][0]) + throw new Exception($"{birthdays[0]} != {destination[propertyId][0]}"); + continue; + } + destination.Add(propertyId, birthdays); + } + json = JsonSerializer.Serialize(destination, jsonSerializerOptions); + File.WriteAllText(namedFaceInfoFile, json); + } + + private static void ReSaveIndexFiles(string infoDirectory, string infoDirectoryIgnore, Dictionary findReplace, List missingIndices) + { + string json; + int propertyId; + Models.SaveTabSeparatedValues.IndexInfo[]? indexCollection; + List indexInfoFiles = Directory.GetFiles(infoDirectory, "IndexInfo.json", SearchOption.AllDirectories).ToList(); + indexInfoFiles.AddRange(Directory.GetFiles(infoDirectoryIgnore, "IndexInfo.json", SearchOption.AllDirectories)); + foreach (string indexInfoFile in indexInfoFiles) + { + json = File.ReadAllText(indexInfoFile); + indexCollection = JsonSerializer.Deserialize(json); + if (indexCollection is null) + continue; + foreach (Models.SaveTabSeparatedValues.IndexInfo indexInfo in indexCollection) + { + if (missingIndices.Contains(indexInfo.Index)) + continue; + propertyId = findReplace[indexInfo.Index]; + indexInfo.Index = propertyId; + } + json = JsonSerializer.Serialize(indexCollection); + File.WriteAllText(indexInfoFile, json); + } + } + + private void ReSaveJsonFiles() + { + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + if (_Configuration?.PropertyConfiguration is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + string? rootDirectoryParent = Path.GetDirectoryName(_Configuration.PropertyConfiguration.RootDirectory); + if (string.IsNullOrEmpty(rootDirectoryParent)) + throw new Exception($"{nameof(rootDirectoryParent)} is null!"); + int z = 0; + int propertyId; + List missingIndices = new(); + Dictionary findReplace = new(); + List useTabSeparatedValueLines = new(); + Dictionary> keyValuePairs = new(); + string tempDirectory = Path.Combine(rootDirectoryParent, "Tmp"); + string useEqualsDirectory = Path.Combine(rootDirectoryParent, "Use - =="); + string use18HoursDirectory = Path.Combine(rootDirectoryParent, "Use - 18 Hours"); + string useAnyDateDirectory = Path.Combine(rootDirectoryParent, "Use - Any Date"); + string imageSharedDirectory = Path.Combine(rootDirectoryParent, "Images - Shared"); + string namedFaceInfoFile = Path.Combine(imageSharedDirectory, "NamedFaceInfo.json"); + string infoDirectory = Path.Combine(imageSharedDirectory, "Images - 4) Info", "2020-06-07"); + string infoDirectoryIgnore = Path.Combine(imageSharedDirectory, "Images - 4) Info - - - Ignore", "2022-04-14"); + Dictionary useTabSeparatedValueCollection = GetUseTabSeparatedValue(useEqualsDirectory, use18HoursDirectory, useAnyDateDirectory, keyValuePairs, useTabSeparatedValueLines); + { + long ticks = DateTime.Now.Ticks; + string json = JsonSerializer.Serialize(keyValuePairs, new JsonSerializerOptions { WriteIndented = true }); + File.WriteAllText($"{tempDirectory}/{nameof(keyValuePairs)}-{ticks}.json", json); + } + List<(int Index, long Ticks, string RelativeDirectory, string FileNameWithoutExtension, string Extension, string RegexResult)> indexCollection = GetIndexCollection(infoDirectory, infoDirectoryIgnore, checkDistinct: true); + foreach ((int index, long ticks, string relativeDirectory, string fileNameWithoutExtension, string extension, string regexResult) in indexCollection) + { + z += 1; + if (_IsEnvironment.Development && z % 1000 == 0) + _Log.Debug($"{z}) Loop {_Configuration.PropertyConfiguration.RootDirectory}"); + if (!useTabSeparatedValueCollection.ContainsKey(index)) + { + missingIndices.Add(index); + continue; + } + propertyId = useTabSeparatedValueCollection[index]; + findReplace.Add(index, propertyId); + } + ReSaveIndexFiles(infoDirectory, infoDirectoryIgnore, findReplace, missingIndices); + ReSaveExifFiles(infoDirectory, infoDirectoryIgnore, findReplace, missingIndices); + ReSaveNamedFaceInfoFile(namedFaceInfoFile, findReplace, missingIndices); + { + long ticks = DateTime.Now.Ticks; + File.WriteAllLines($"{tempDirectory}/{nameof(useTabSeparatedValueLines)}-{ticks}.tsv", useTabSeparatedValueLines); + File.WriteAllText($"{tempDirectory}/{nameof(missingIndices)}-{ticks}.txt", string.Join(Environment.NewLine, missingIndices)); + } + _Log.Debug($"Done with {nameof(ReSaveJsonFiles)}"); + } + + private void CopyMissingImagesLogs() + { + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + if (_Configuration?.PropertyConfiguration is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + string? rootDirectoryParent = Path.GetDirectoryName(_Configuration.PropertyConfiguration.RootDirectory); + if (_Configuration?.PropertyConfiguration is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + if (string.IsNullOrEmpty(rootDirectoryParent)) + throw new Exception($"{nameof(rootDirectoryParent)} is null!"); + int z = 0; + int propertyId; + Dictionary findReplace = new(); + List missingIndices = new(); + List useTabSeparatedValueLines = new(); + Dictionary> keyValuePairs = new(); + string tempDirectory = Path.Combine(rootDirectoryParent, "Tmp"); + string currentDirectory = Path.Combine(rootDirectoryParent, "@) Images"); + string useEqualsDirectory = Path.Combine(rootDirectoryParent, "Use - =="); + string use18HoursDirectory = Path.Combine(rootDirectoryParent, "Use - 18 Hours"); + string useAnyDateDirectory = Path.Combine(rootDirectoryParent, "Use - Any Date"); + string imageSharedDirectory = Path.Combine(rootDirectoryParent, "Images - Shared"); + string namedFaceInfoFile = Path.Combine(imageSharedDirectory, "NamedFaceInfo.json"); + string infoDirectory = Path.Combine(imageSharedDirectory, "Images - 4) Info", "2020-06-07"); + string infoDirectoryIgnore = Path.Combine(imageSharedDirectory, "Images - 4) Info - - - Ignore", "2022-04-14"); + Dictionary useTabSeparatedValueCollection = GetUseTabSeparatedValue(useEqualsDirectory, use18HoursDirectory, useAnyDateDirectory, keyValuePairs, useTabSeparatedValueLines); + { + long ticks = DateTime.Now.Ticks; + string json = JsonSerializer.Serialize(keyValuePairs, new JsonSerializerOptions { WriteIndented = true }); + File.WriteAllText($"{tempDirectory}/{nameof(keyValuePairs)}-{ticks}.json", json); + } + List<(int Index, long Ticks, string RelativeDirectory, string FileNameWithoutExtension, string Extension, string RegexResult)> indexCollection = GetIndexCollection(infoDirectory, infoDirectoryIgnore, checkDistinct: false); + foreach ((int index, long ticks, string relativeDirectory, string fileNameWithoutExtension, string extension, string regexResult) in indexCollection) + { + z += 1; + if (_IsEnvironment.Development && z % 1000 == 0) + _Log.Debug($"{z}) Loop {_Configuration.PropertyConfiguration.RootDirectory}"); + if (!useTabSeparatedValueCollection.ContainsKey(index)) + { + missingIndices.Add(index); + continue; + } + propertyId = useTabSeparatedValueCollection[index]; + findReplace.Add(index, propertyId); + } + { + long ticks = DateTime.Now.Ticks; + File.WriteAllLines($"{tempDirectory}/{nameof(useTabSeparatedValueLines)}-{ticks}.tsv", useTabSeparatedValueLines); + File.WriteAllText($"{tempDirectory}/{nameof(missingIndices)}-{ticks}.txt", string.Join(Environment.NewLine, missingIndices)); + } + _Log.Debug($"Done with {nameof(CopyMissingImagesLogs)}"); + } + + private static Dictionary> GetKeyValuePairs(PropertyCompare.Models.PropertyCompare[] propertyCompares) + { + Dictionary> results = new(); + foreach (PropertyCompare.Models.PropertyCompare propertyCompare in propertyCompares) + { + if (propertyCompare?.Property?.Id is null) + continue; + if (!results.ContainsKey(propertyCompare.Property.Id.Value)) + results.Add(propertyCompare.Property.Id.Value, new()); + results[propertyCompare.Property.Id.Value].Add(propertyCompare); + } + return results; + } + + private void VerifyAgainstIndexInfoJsonFiles(Property.Models.Configuration configuration, string aPropertySingletonDirectory) + { + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + if (_AppSettings.MaxDegreeOfParallelism is null) + throw new Exception($"{nameof(_AppSettings.MaxDegreeOfParallelism)} is null!"); + if (_Configuration?.PropertyConfiguration is null) + throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + string? rootDirectoryParent = Path.GetDirectoryName(_Configuration.PropertyConfiguration.RootDirectory); + if (string.IsNullOrEmpty(rootDirectoryParent)) + throw new Exception($"{nameof(rootDirectoryParent)} is null!"); + int z = 0; + int? propertyId; + long? propertyTicks; + int loadLessThan = 7; + string diffRootDirectory = string.Empty; + PropertyCompare.Models.PropertyCompare propertyCompare; + string tempDirectory = Path.Combine(rootDirectoryParent, "Tmp"); + if (!Directory.Exists(tempDirectory)) + _ = Directory.CreateDirectory(tempDirectory); + string imageSharedDirectory = Path.Combine(rootDirectoryParent, "Images - Shared"); + string namedFaceInfoFile = Path.Combine(imageSharedDirectory, "NamedFaceInfo.json"); + string infoDirectory = Path.Combine(imageSharedDirectory, "Images - 4) Info", "2020-06-07"); + List<(int Index, string RelativeDirectory, string FileName, string RegexResult, long Ticks, int? PropertyId, long? PropertyTicks)> collection = new(); + PropertyCompare.Models.PropertyCompareLogic propertyCompareLogic = new(_AppSettings.MaxDegreeOfParallelism.Value, _Configuration.PropertyConfiguration, _SpellingFindReplace, diffRootDirectory); + PropertyCompare.Models.PropertyCompare[] propertyCompareCollection = propertyCompareLogic.Get(aPropertySingletonDirectory, loadLessThan); + { + long ticks = DateTime.Now.Ticks; + string[] lines = (from l in propertyCompareCollection select l.GetSelect()).ToArray(); + string aPropertyCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "[{}]"); + File.WriteAllLines(Path.Join(aPropertyCollectionDirectory, $". . . Ids - {ticks}.txt"), lines); + string json = JsonSerializer.Serialize(propertyCompareCollection, new JsonSerializerOptions { WriteIndented = true }); + File.WriteAllText(Path.Join(aPropertyCollectionDirectory, $". . . Ids - {ticks}.nosj"), json); + } + Dictionary> keyValuePairs = GetKeyValuePairs(propertyCompareCollection); + List<(int Index, long Ticks, string RelativeDirectory, string FileNameWithoutExtension, string Extension, string RegexResult)> indexCollection = GetIndexCollection(infoDirectory, infoDirectoryExtra: string.Empty, checkDistinct: false); + foreach ((int index, long ticks, string relativeDirectory, string fileNameWithoutExtension, string extension, string regexResult) in indexCollection) + { + z += 1; + if (_IsEnvironment.Development && z % 1000 == 0) + _Log.Debug($"{z}) Loop {_Configuration.PropertyConfiguration.RootDirectory}"); + propertyId = null; + propertyTicks = null; + if (keyValuePairs.ContainsKey(index)) + { + propertyCompare = keyValuePairs[index][0]; + if (propertyCompare?.Property?.Id is null) + continue; + propertyId = propertyCompare.Property.Id; + propertyTicks = propertyCompare.MinimumDateTime.Ticks; + } + collection.Add(new(index, relativeDirectory, $"{fileNameWithoutExtension}{extension}", regexResult, ticks, propertyId, propertyTicks)); + } + (int Index, string RelativeDirectory, string FileName, string RegexResult, long Ticks, int? PropertyId, long? PropertyTicks)[] matched = (from l in collection where l.PropertyId.HasValue select l).ToArray(); + (int Index, string RelativeDirectory, string FileName, string RegexResult, long Ticks, int? PropertyId, long? PropertyTicks)[] notMatched = (from l in collection where l.PropertyId is null select l).ToArray(); + string[] matchedLines = ( + from l + in matched + select $"{l.Index}\t{l.PropertyId}\t{l.RegexResult}\t{new DateTime(l.Ticks):yyyy-MM-dd_HH-mm-ss}\t{l.PropertyTicks}\t{l.RelativeDirectory}\t{l.FileName}" + ).ToArray(); + List notMatchedLines = ( + from l + in notMatched + select $"{l.Index}\t______________\t{l.RegexResult}\t{new DateTime(l.Ticks):yyyy-MM-dd_HH-mm-ss}\t_________________\t{l.RelativeDirectory}\t{l.FileName}" + ).ToList(); + { + long ticks = DateTime.Now.Ticks; + File.WriteAllLines($"{tempDirectory}/{collection.Count}-{ticks}.tsv", matchedLines); + File.WriteAllLines($"{tempDirectory}/{collection.Count}-{ticks}-Not.tsv", notMatchedLines); + } + _Log.Debug($"Done with {nameof(VerifyAgainstIndexInfoJsonFiles)}"); + } + +} \ No newline at end of file diff --git a/PrepareForOld/PrepareForOld.csproj b/PrepareForOld/PrepareForOld.csproj new file mode 100644 index 0000000..c4fffbc --- /dev/null +++ b/PrepareForOld/PrepareForOld.csproj @@ -0,0 +1,60 @@ + + + enable + 10.0 + enable + Exe + win-x64 + net6.0 + + + Phares.View.by.Distance.PrepareForOld + false + 5.0.402.104 + Mike Phares + Phares + true + snupkg + + + true + true + true + + + Windows + + + OSX + + + Linux + + + + + + + + + + + + + + + + + + + + + + + + + + Always + + + \ No newline at end of file diff --git a/PrepareForOld/Program.cs b/PrepareForOld/Program.cs new file mode 100644 index 0000000..ed23c36 --- /dev/null +++ b/PrepareForOld/Program.cs @@ -0,0 +1,71 @@ +using Microsoft.Extensions.Configuration; +using Phares.Shared; +using Serilog; +using System.Diagnostics; +using System.Reflection; +using View_by_Distance.PrepareForOld.Models; +using View_by_Distance.Shared.Models.Stateless.Methods; + +namespace View_by_Distance.PrepareForOld; + +public class Program +{ + + public static void Secondary(List args) + { + LoggerConfiguration loggerConfiguration = new(); + Assembly assembly = Assembly.GetExecutingAssembly(); + bool debuggerWasAttachedAtLineZero = Debugger.IsAttached || assembly.Location.Contains(@"\bin\Debug"); + IsEnvironment isEnvironment = new(processesCount: null, nullASPNetCoreEnvironmentIsDevelopment: debuggerWasAttachedAtLineZero, nullASPNetCoreEnvironmentIsProduction: !debuggerWasAttachedAtLineZero); + IConfigurationBuilder configurationBuilder = new ConfigurationBuilder() + .AddEnvironmentVariables() + .AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true); + IConfigurationRoot configurationRoot = configurationBuilder.Build(); + AppSettings appSettings = Models.Stateless.AppSettings.Get(configurationRoot); + if (appSettings.MaxDegreeOfParallelism is null) + throw new Exception("MaxDegreeOfParallelism must be set!"); + if (appSettings.MaxDegreeOfParallelism.Value > Environment.ProcessorCount) + throw new Exception("MaxDegreeOfParallelism must be =< Environment.ProcessorCount!"); + if (string.IsNullOrEmpty(appSettings.WorkingDirectoryName)) + throw new Exception("Working directory name must have a value!"); + string workingDirectory = IWorkingDirectory.GetWorkingDirectory(assembly.GetName().Name, appSettings.WorkingDirectoryName); + Environment.SetEnvironmentVariable(nameof(workingDirectory), workingDirectory); + _ = ConfigurationLoggerConfigurationExtensions.Configuration(loggerConfiguration.ReadFrom, configurationRoot); + Log.Logger = loggerConfiguration.CreateLogger(); + ILogger log = Log.ForContext(); + int silentIndex = args.IndexOf("s"); + if (silentIndex > -1) + args.RemoveAt(silentIndex); + try + { + if (args is null) + throw new Exception("args is null!"); + Shared.Models.Console console = new(); + PrepareForOld dlibDotNet = new(args, isEnvironment, configurationRoot, appSettings, workingDirectory, silentIndex > -1, console); + } + catch (Exception ex) + { + log.Fatal(string.Concat(ex.Message, Environment.NewLine, ex.StackTrace)); + } + finally + { + Log.CloseAndFlush(); + } + if (silentIndex > -1) + log.Debug("Done. Bye"); + else + { + log.Debug("Done. Press 'Enter' to end"); + _ = Console.ReadLine(); + } + } + + public static void Main(string[] args) + { + if (args is not null) + Secondary(args.ToList()); + else + Secondary(new List()); + } + +} \ No newline at end of file diff --git a/PrepareForOld/appsettings.Development.json b/PrepareForOld/appsettings.Development.json new file mode 100644 index 0000000..4a7b4e1 --- /dev/null +++ b/PrepareForOld/appsettings.Development.json @@ -0,0 +1,364 @@ +{ + "Company": "Mike Phares", + "Linux": {}, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Log4netProvider": "Debug", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "MaxDegreeOfParallelism": 6, + "Serilog": { + "Using": [ + "Serilog.Sinks.Console", + "Serilog.Sinks.File" + ], + "MinimumLevel": "Debug", + "WriteTo": [ + { + "Name": "Debug", + "Args": { + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}" + } + }, + { + "Name": "Console", + "Args": { + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "%workingDirectory% - Log/log-.txt", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}", + "rollingInterval": "Hour" + } + } + ], + "Enrich": [ + "FromLogContext", + "WithMachineName", + "WithThreadId" + ], + "Properties": { + "Application": "Sample" + } + }, + "WorkingDirectoryName": "PharesApps", + "Windows": { + "Configuration": { + "DateGroup": "2022-04-07", + "FileNameDirectorySeparator": ".Z.", + "ForcePropertyLastWriteTimeToCreationTime": false, + "KeepFullPath": false, + "MaxImagesInDirectoryForTopLevelFirstPass": 50, + "Pattern": "[^ABCDEFGHIJKLMNOPQRSTUVWXYZbcdfghjklmnpqrstvwxyz0-9]", + "PopulatePropertyId": false, + "PropertiesChangedForProperty": false, + "RootDirectory": "C:/Tmp/Phares/Pictures", + "WriteBitmapDataBytes": false, + "IgnoreExtensions": [ + ".gif", + ".GIF" + ], + "PropertyContentCollectionFiles": [], + "Spelling": [ + "Bday", + "Birthday", + "Childrens", + "Children's", + "Darrens", + "Darren's", + "Febuary", + "February", + "Feburay", + "February", + "Frist", + "First", + "Goolgle", + "Google", + "Kristys", + "Kristy's", + "Micael's", + "Michael's", + "Origanls", + "Originals", + "Patrict", + "Patrick", + "Sebtember", + "September" + ], + "ValidImageFormatExtensions": [ + ".bmp", + ".BMP", + ".gif", + ".GIF", + ".jpeg", + ".JPEG", + ".jpg", + ".JPG", + ".png", + ".PNG", + ".tiff", + ".TIFF" + ], + "ValidMetadataExtensions": [ + ".3gp", + ".3GP", + ".amr", + ".AMR", + ".avi", + ".AVI", + ".bmp", + ".BMP", + ".gif", + ".GIF", + ".ico", + ".ICO", + ".jpeg", + ".JPEG", + ".jpg", + ".JPG", + ".m4v", + ".M4V", + ".mov", + ".MOV", + ".mp4", + ".MP4", + ".mta", + ".MTA", + ".png", + ".PNG", + ".tiff", + ".TIFF" + ], + "VerifyToSeason": [ + ". 2000", + ". 2001", + ". 2002", + ". 2003", + ". 2004", + ". 2005", + ". 2006", + ". 2007", + ". 2008", + ". 2009", + ". 2010", + ". 2011", + ". 2012", + ". 2013", + ". 2014", + ". 2015", + ". 2016", + ". 2017", + ". 2018", + ". 2019", + ". 2020", + ". 2021", + ". 2022", + ". 2023", + ". 2024", + ". 2025", + ". 2026", + ". 2027", + ". 2028", + ". 2029", + "=2000.0 Winter", + "=2002.1 Spring", + "=2002.4 Winter", + "=2003.0 Winter", + "=2003.1 Spring", + "=2003.3 Fall", + "=2003.4 Winter", + "=2004.0 Winter", + "=2005.1 Spring", + "=2005.2 Summer", + "=2005.3 Fall", + "=2005.4 Winter", + "=2006.0 Winter", + "=2006.1 Spring", + "=2006.3 Fall", + "=2007.0 Winter", + "=2007.2 Summer Logan Michael", + "=2007.2 Summer", + "=2007.3 Fall Logan Michael", + "=2007.4 Winter Logan Michael", + "=2008.0 Winter Logan Michael", + "=2008.1 Spring Logan Michael", + "=2008.2 Summer Logan Michael", + "=2008.2 Summer", + "=2008.3 Fall Logan Michael", + "=2009.0 Winter Logan Michael", + "=2009.0 Winter", + "=2009.1 Spring Logan Michael", + "=2009.1 Spring", + "=2009.2 Summer Logan Michael", + "=2009.2 Summer", + "=2009.3 Fall Logan Michael", + "=2009.3 Fall", + "=2009.4 Winter Logan Michael", + "=2009.4 Winter", + "=2010.0 Winter Logan Michael", + "=2010.0 Winter", + "=2010.1 Spring Logan Michael", + "=2010.1 Spring", + "=2010.2 Summer", + "=2010.3 Fall Logan Michael", + "=2010.3 Fall", + "=2010.4 Winter", + "=2011.0 Winter", + "=2011.1 Spring", + "=2011.2 Summer", + "=2011.3 Fall", + "=2011.4 Winter", + "=2012.0 Winter Chelsea 2012", + "=2012.0 Winter Chelsea", + "=2012.0 Winter", + "=2012.1 Spring Chelsea", + "=2012.1 Spring", + "=2012.2 Summer Chelsea", + "=2012.2 Summer", + "=2012.3 Fall Chelsea", + "=2012.3 Fall", + "=2012.4 Winter Chelsea", + "=2012.4 Winter", + "=2013.0 Winter Chelsea 2013", + "=2013.0 Winter Chelsea", + "=2013.0 Winter", + "=2013.1 Spring", + "=2013.2 Summer Chelsea", + "=2013.2 Summer", + "=2013.3 Fall Chelsea", + "=2013.3 Fall", + "=2013.4 Winter", + "=2014.0 Winter", + "=2014.1 Spring", + "=2014.2 Summer", + "=2014.3 Fall", + "=2014.4 Winter", + "=2015.0 Winter", + "=2015.1 Spring", + "=2015.2 Summer", + "=2015.3 Fall", + "=2015.4 Winter", + "=2016.0 Winter", + "=2016.1 Spring", + "=2016.2 Summer", + "=2016.3 Fall", + "=2016.4 Winter", + "=2017.1 Spring", + "=2017.2 Summer", + "=2017.3 Fall", + "=2017.4 Winter", + "=2018.0 Winter", + "=2018.1 Spring", + "=2018.3 Fall", + "=2018.4 Winter", + "=2019.0 Winter", + "=2019.1 Spring", + "=2019.2 Summer", + "=2019.3 Fall", + "=2019.4 Winter", + "=2020.0 Winter", + "=2020.1 Spring", + "=2020.2 Summer", + "=2020.3 Fall", + "=2020.4 Winter", + "=2021.1 Spring", + "=2021.2 Summer", + "=2021.3 Fall", + "=2021.4 Winter", + "=2022.0 Winter", + "=2022.1 Spring", + "Anthem 2015", + "April 2010", + "April 2013", + "December 2006", + "December 2010", + "Fall 2005", + "Fall 2015", + "Fall 2016", + "Fall 2017", + "Fall 2018", + "Fall 2019", + "Fall 2020", + "Fall 2021", + "February 2010", + "January 2015", + "July 2010", + "June 2010", + "Kids 2005", + "March 2013", + "May 2010", + "May 2011", + "May 2013", + "October 2005", + "October 2014", + "Spring 2013", + "Spring 2014", + "Spring 2016", + "Spring 2018", + "Spring 2019", + "Spring 2020", + "Summer 2011", + "Summer 2012", + "Summer 2013", + "Summer 2014", + "Summer 2015", + "Summer 2016", + "Summer 2017", + "Summer 2018", + "Summer 2020", + "Summer 2021", + "Winter 2015", + "Winter 2016", + "Winter 2017", + "Winter 2018", + "Winter 2019-2020", + "Winter 2020", + "zzz =2005.0 Winter Tracy Pictures", + "zzz =2005.1 Spring Tracy Pictures", + "zzz =2005.2 Summer Tracy Pictures", + "zzz =2005.3 Fall Tracy Pictures", + "zzz =2005.4 Winter Tracy Pictures", + "zzz =2006.1 Spring Tracy Pictures", + "zzz =2007.0 Winter Tracy Pictures", + "zzz =2007.2 Summer Tracy Pictures", + "zzz =2008.0 Winter Tracy Pictures", + "zzz =2008.2 Summer Tracy Pictures", + "zzz =2009.0 Winter Tracy Pictures", + "zzz =2009.2 Summer Tracy Pictures", + "zzz =2009.3 Fall Tracy Pictures", + "zzz =2009.4 Winter Tracy Pictures", + "zzz =2010.0 Winter Tracy Pictures", + "zzz =2010.1 Spring Tracy Pictures", + "zzz =2010.2 Summer Tracy Pictures", + "zzz =2010.3 Fall Tracy Pictures", + "zzz =2011.0 Winter Tracy Pictures", + "zzz =2011.1 Spring Tracy Pictures", + "zzz =2011.2 Summer Tracy Pictures", + "zzz =2011.3 Fall Tracy Pictures", + "zzz =2011.4 Winter Tracy Pictures", + "zzz =2012.0 Winter Tracy Pictures", + "zzz =2012.1 Spring Tracy Pictures", + "zzz =2012.2 Summer Tracy Pictures", + "zzz =2012.3 Fall Tracy Pictures", + "zzz =2012.4 Winter Tracy Pictures", + "zzz =2013.0 Winter Tracy Pictures", + "zzz =2013.1 Spring Tracy Pictures", + "zzz =2013.2 Summer Tracy Pictures", + "zzz =2013.3 Fall Tracy Pictures", + "zzz =2013.4 Winter Tracy Pictures", + "zzz =2014.0 Winter Tracy Pictures", + "zzz =2014.1 Spring Tracy Pictures", + "zzz =2014.2 Summer Tracy Pictures", + "zzz =2014.3 Fall Tracy Pictures", + "zzz =2014.4 Winter Tracy Pictures", + "zzz =2015.0 Winter Tracy Pictures" + ] + } + } +} \ No newline at end of file diff --git a/Property-Compare/.vscode/format-report.json b/Property-Compare/.vscode/format-report.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/Property-Compare/.vscode/format-report.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/Property-Compare/.vscode/settings.json b/Property-Compare/.vscode/settings.json new file mode 100644 index 0000000..0852522 --- /dev/null +++ b/Property-Compare/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "cSpell.words": [ + "dlib", + "Exif", + "nosj", + "Serilog" + ] +} \ No newline at end of file diff --git a/Property-Compare/Models/PropertyCompare.cs b/Property-Compare/Models/PropertyCompare.cs new file mode 100644 index 0000000..c07cfc1 --- /dev/null +++ b/Property-Compare/Models/PropertyCompare.cs @@ -0,0 +1,56 @@ +using System.Text.Json; +using View_by_Distance.Property.Models; + +namespace View_by_Distance.PropertyCompare.Models; + +public partial class PropertyCompare +{ + + protected string _Extension; + protected string _FileNameWithoutExtension; + protected readonly bool _IsArg; + protected DateTime _MinimumDateTime; + protected readonly List _Numbers; + protected A_Property? _Property; + protected string _RegexResult; + protected string _RelativeDirectory; + protected readonly List _Strings; + + public string Extension => _Extension; + public string FileNameWithoutExtension => _FileNameWithoutExtension; + public bool IsArg => _IsArg; + public DateTime MinimumDateTime => _MinimumDateTime; + public List Numbers => _Numbers; + public A_Property? Property => _Property; + public string RegexResult => _RegexResult; + public string RelativeDirectory => _RelativeDirectory; + public List Strings => _Strings; + + public PropertyCompare(string extension, string fileNameWithoutExtension, bool isArg, DateTime minimumDateTime, List numbers, A_Property property, string regexResult, string relativeDirectory, List strings) + { + _IsArg = isArg; + _Numbers = numbers; + _Strings = strings; + _Property = property; + _Extension = extension; + _RegexResult = regexResult; + _MinimumDateTime = minimumDateTime; + _RelativeDirectory = relativeDirectory; + _FileNameWithoutExtension = fileNameWithoutExtension; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + + // internal static string GetSelect(PropertyCompare item) => string.Concat(item.JsonFileNameWithoutExtension, item.ImageFileName, '\t', item.Property.CreationTime.Ticks, '\t', GetDateTime(item.Property).ToString("yyyy-MM-dd_HH-mm-ss"), '\t', item.Property.Id, '\t', item.Property.FileSize, '\t', item.Property.Width, '\t', item.Property.Height); + +#nullable disable + + public string GetSelect() => string.Concat(_RelativeDirectory, _FileNameWithoutExtension, _Extension, '\t', _Property.CreationTime.Ticks, '\t', View_by_Distance.Property.Models.Stateless.A_Property.GetDateTime(_Property).ToString("yyyy-MM-dd_HH-mm-ss"), '\t', _Property.Id, '\t', _Property.FileSize, '\t', _Property.Width, '\t', _Property.Height); + +#nullable restore + +} \ No newline at end of file diff --git a/Property-Compare/Models/PropertyCompareItem.cs b/Property-Compare/Models/PropertyCompareItem.cs new file mode 100644 index 0000000..09e8b70 --- /dev/null +++ b/Property-Compare/Models/PropertyCompareItem.cs @@ -0,0 +1,31 @@ +using View_by_Distance.Property.Models; + +namespace View_by_Distance.PropertyCompare.Models; + +internal class PropertyCompareItem +{ + + protected readonly string _ImageFileName; + protected readonly bool _IsArg; + protected readonly string _JsonFileNameWithoutExtension; + protected readonly long[] _Numbers; + protected readonly A_Property _Property; + protected readonly string[] _Strings; + public string ImageFileName => _ImageFileName; + public bool IsArg => _IsArg; + public string JsonFileNameWithoutExtension => _JsonFileNameWithoutExtension; + public long[] Numbers => _Numbers; + public A_Property Property => _Property; + public string[] Strings => _Strings; + + public PropertyCompareItem(string imageFileName, bool isArg, string jsonFileNameWithoutExtension, long[] numbers, A_Property property, string[] strings) + { + _ImageFileName = imageFileName; + _IsArg = isArg; + _JsonFileNameWithoutExtension = jsonFileNameWithoutExtension; + _Numbers = numbers; + _Property = property; + _Strings = strings; + } + +} \ No newline at end of file diff --git a/Property-Compare/Models/PropertyCompareLogic.cs b/Property-Compare/Models/PropertyCompareLogic.cs new file mode 100644 index 0000000..cd22e7f --- /dev/null +++ b/Property-Compare/Models/PropertyCompareLogic.cs @@ -0,0 +1,609 @@ +using ShellProgressBar; +using System.Text.Json; +using System.Text.RegularExpressions; +using View_by_Distance.Property.Models; + +namespace View_by_Distance.PropertyCompare.Models; + +public class PropertyCompareLogic +{ + + private readonly Serilog.ILogger? _Log; + private readonly string? _DiffRootDirectory; + private readonly int _MaxDegreeOfParallelism; + private readonly Configuration _Configuration; + private readonly List<(string Find, string Replace)>? _SpellingFindReplace; + + public PropertyCompareLogic(int maxDegreeOfParallelism, Configuration configuration, List<(string Find, string Replace)>? spellingFindReplace = null, string? diffRootDirectory = null) + { + _Configuration = configuration; + _DiffRootDirectory = diffRootDirectory; + _SpellingFindReplace = spellingFindReplace; + _Log = Serilog.Log.ForContext(); + _MaxDegreeOfParallelism = Math.Abs(maxDegreeOfParallelism); + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + + private List GetDuplicates(PropertyCompare[] propertyCompares, int i, PropertyCompare[]? diffPropertyCompares) + { + List results = new(); + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + int index; + string value; + long[] distinctNumberValues; + List checkValues = new(); + List checkNumberValues = new(); + if (diffPropertyCompares is null || propertyCompares.Length != diffPropertyCompares.Length) + { + foreach (PropertyCompare propertyCompare in propertyCompares) + { + value = $"{propertyCompare.Numbers[i]}\t{propertyCompare.Strings[i]}"; + checkNumberValues.Add(propertyCompare.Numbers[i]); + checkValues.Add(value); + } + distinctNumberValues = checkNumberValues.Distinct().ToArray(); + if (distinctNumberValues.Length != propertyCompares.Length) + _Log.Debug($"A) Distinct {nameof(propertyCompares)} - <{distinctNumberValues.Length} != {propertyCompares.Length}>"); + } + if (diffPropertyCompares is not null) + { + foreach (PropertyCompare propertyCompare in diffPropertyCompares) + { + value = $"{propertyCompare.Numbers[i]}\t{propertyCompare.Strings[i]}"; + if (checkNumberValues.Contains(propertyCompare.Numbers[i])) + { + index = checkValues.IndexOf(value); + if (index > -1) + { + if (index >= propertyCompares.Length - 1) + continue; + results.Add(propertyCompare); + results.Add(propertyCompares[index]); + } + } + checkNumberValues.Add(propertyCompare.Numbers[i]); + checkValues.Add(value); + } + distinctNumberValues = checkNumberValues.Distinct().ToArray(); + if (distinctNumberValues.Length != propertyCompares.Length) + _Log.Debug($"B) Distinct {nameof(propertyCompares)} - <{distinctNumberValues.Length} != {propertyCompares.Length}>"); + } + return results; + } + + private (string[] ToDirectories, List FromThenToCollection) Get(string aPropertyCollectionDirectory, PropertyCompare[] propertyCompares, int i, PropertyCompare[]? diffPropertyCompares) + { + List fromThenToCollection = new(); + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + int z = 0; + string to; + string from; + bool extensionIsNullOrEmpty; + string fileName; + string toDirectory; + string fromDirectory; + List toCollection = new(); + List toDirectories = new(); + List fromCollection = new(); + List bothCollection = new(); + foreach (PropertyCompare propertyCompare in propertyCompares) + bothCollection.Add(propertyCompare); + if (diffPropertyCompares is not null) + { + foreach (PropertyCompare propertyCompare in diffPropertyCompares) + bothCollection.Add(propertyCompare); + } + foreach (PropertyCompare propertyCompare in bothCollection) + { + z += 1; + if (z % 1000 == 0) + { + if (!propertyCompare.IsArg) + _Log.Debug($"{z}) Loop {_DiffRootDirectory}"); + else + _Log.Debug($"{z}) Loop {_Configuration.RootDirectory}"); + } + extensionIsNullOrEmpty = string.IsNullOrEmpty(propertyCompare.Extension); + if (propertyCompare.IsArg) + fromDirectory = string.Concat(_Configuration.RootDirectory, propertyCompare.RelativeDirectory); + else + fromDirectory = string.Concat(_DiffRootDirectory, propertyCompare.RelativeDirectory); + if (!Directory.Exists(fromDirectory)) + _ = Directory.CreateDirectory(fromDirectory); + to = string.Empty; + if (extensionIsNullOrEmpty) + from = Path.GetFullPath(Path.Combine(fromDirectory, $"{propertyCompare.FileNameWithoutExtension}.jpg")); + else + from = Path.GetFullPath(Path.Combine(fromDirectory, $"{propertyCompare.FileNameWithoutExtension}{propertyCompare.Extension}")); + if (fromCollection.Contains(from)) + continue; + if (!extensionIsNullOrEmpty && !File.Exists(from)) + continue; + fromCollection.Add(from); + for (short c = 65; c < short.MaxValue; c++) + { + if (c > 95) + break; + if (extensionIsNullOrEmpty && !propertyCompare.IsArg) + c += 1; + fileName = Regex.Replace(propertyCompare.Strings[i], @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]", "_"); + toDirectory = Path.Combine(aPropertyCollectionDirectory, $". . . {i} - {(char)c}"); + if (!extensionIsNullOrEmpty) + to = Path.GetFullPath(Path.Combine(toDirectory, $"{propertyCompare.Numbers[i]}{fileName}{propertyCompare.Extension.ToLower()}")); + else + { + to = Path.GetFullPath(Path.Combine(toDirectory, $"{propertyCompare.Numbers[i]}{fileName}.jpg")); + break; + } + if (toCollection.Contains(to)) + continue; + if (!toDirectories.Contains(toDirectory)) + toDirectories.Add(toDirectory); + toCollection.Add(to); + break; + } + if (string.IsNullOrEmpty(to)) + continue; + fromThenToCollection.Add(new string[] { from, to }); + } + return new(toDirectories.ToArray(), fromThenToCollection); + } + + private void ParallelGet(List? duplicates, List results, List ids, List collection, int loadLessThan, string directory, object @lock, string relativeDirectory, string[] files, List filesWithoutExtension, bool isArg, string jsonFile) + { + long n; + string s; + int index; + string extension; + string corrected; + List numbers; + string regexResult; + List strings; + PropertyCompare propertyCompare; + string jsonFileNameWithoutExtension = Path.GetFileNameWithoutExtension(jsonFile); + string check = Path.Combine(directory, jsonFileNameWithoutExtension); + index = filesWithoutExtension.IndexOf(check); + if (index == -1) + extension = string.Empty; + else + extension = Path.GetExtension(files[index]); + string json = File.ReadAllText(jsonFile); + A_Property? property = JsonSerializer.Deserialize(json); + if (property?.Id is null) + throw new Exception($"{nameof(property)} is null!"); + DateTime minimumDateTime = Property.Models.Stateless.A_Property.GetMinimumDateTime(property); + corrected = string.Concat(relativeDirectory, jsonFileNameWithoutExtension); + if (_SpellingFindReplace is not null && (from l in _SpellingFindReplace where corrected.Contains(l.Find) select true).Any()) + { + foreach ((string find, string replace) in _SpellingFindReplace) + corrected = corrected.Replace(find, replace); + } + if (string.IsNullOrEmpty(_Configuration.Pattern)) + regexResult = corrected; + else + regexResult = Regex.Replace(corrected, _Configuration.Pattern, string.Empty); + numbers = new(); + strings = new(); + for (int i = 0; i < loadLessThan; i++) + { + n = i switch + { + 0 => property.Id.Value, + 1 => property.Id.Value, + 2 => property.Id.Value, + 3 => property.Id.Value, + 4 => property.Id.Value, + 5 => Property.Models.Stateless.A_Property.GetDateTime(property).Ticks, + 6 => property.CreationTime.Ticks, + 7 => property.FileSize, + 8 => Property.Models.Stateless.A_Property.GetDateTime(property).Ticks, + 9 => property.FileSize, + _ => throw new Exception() + }; + s = i switch + { + 0 => $"{jsonFileNameWithoutExtension.ToLower()}", + 1 => $"{property.FileSize}{Property.Models.Stateless.A_Property.GetDateTime(property).Ticks}", + 2 => $"{property.FileSize}{property.CreationTime:yyyy-MM-dd_HH-mm-ss}", + 3 => $"{property.FileSize}{property.Width}{property.Height}", + 4 => string.Empty, + 5 => $"{property.FileSize}", + 6 => $"{property.FileSize}", + 7 => $"{property.Width}{property.Height}", + 8 => string.Empty, + 9 => string.Empty, + _ => throw new Exception() + }; + numbers.Add(n); + strings.Add(s); + } + propertyCompare = new(extension, jsonFileNameWithoutExtension, isArg, minimumDateTime, numbers, property, regexResult, relativeDirectory, strings); + lock (@lock) + results.Add(propertyCompare); + if (duplicates is not null) + { + string value = $"{property.Id.Value}\t{property}"; + index = ids.IndexOf(property.Id.Value); + if (index > -1) + { + lock (@lock) + { + duplicates.Add(propertyCompare); + duplicates.Add(collection[index]); + } + } + lock (@lock) + { + ids.Add(property.Id.Value); + collection.Add(propertyCompare); + } + } + } + + public PropertyCompare[] Get(string aPropertySingletonDirectory, int loadLessThan = 7, List? duplicates = null, bool deleteExtension = false) + { + List results = new(); + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + string[] files; + int totalSeconds; + string directory; + string searchPattern; + object @lock = new(); + int exceptionCount = 0; + List ids = new(); + string relativeDirectory; + if (!deleteExtension) + searchPattern = "*.json"; + else + searchPattern = "*.delete"; + long ticks = DateTime.Now.Ticks; + List filesWithoutExtension; + List topDirectories = new(); + string extension = searchPattern[1..]; + string[] filteredSourceDirectoryFiles; + List collection = new(); + bool isArg = aPropertySingletonDirectory.Contains(_Configuration.RootDirectory); + ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = _MaxDegreeOfParallelism }; + ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; + List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> groupCollection = Property.Models.Stateless.A_Property.GetGroupCollection(aPropertySingletonDirectory, searchPattern, topDirectories); + int count = groupCollection.Count; + foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles, int r) in groupCollection) + { + if (!topDirectories.Any()) + continue; + if (!sourceDirectoryFiles.Any()) + continue; + relativeDirectory = sourceDirectory[aPropertySingletonDirectory.Length..]; + if (!isArg) + directory = string.Concat(_DiffRootDirectory, relativeDirectory); + else + directory = string.Concat(_Configuration.RootDirectory, relativeDirectory); + if (!Directory.Exists(directory)) + _ = Directory.CreateDirectory(directory); + files = Directory.GetFiles(directory); + filesWithoutExtension = files.Select(l => Path.Combine($"{Path.GetDirectoryName(l)}", Path.GetFileNameWithoutExtension(l))).ToList(); + filteredSourceDirectoryFiles = (from l in sourceDirectoryFiles where l.EndsWith(extension) select l).ToArray(); + if (!filteredSourceDirectoryFiles.Any()) + continue; + totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); + using ProgressBar progressBar = new(filteredSourceDirectoryFiles.Length, $"{g}) {r + 1:000} / {count:000} - {sourceDirectory} - {filteredSourceDirectoryFiles.Length} file(s) - {totalSeconds} total second(s)", options); + _ = Parallel.For(0, filteredSourceDirectoryFiles.Length, parallelOptions, i => + { + try + { + ParallelGet(duplicates, results, ids, collection, loadLessThan, directory, @lock, relativeDirectory, files, filesWithoutExtension, isArg, sourceDirectoryFiles[i]); + progressBar.Tick(); + } + catch (Exception ex) + { + exceptionCount += 1; + _Log.Error(string.Concat(sourceDirectory, Environment.NewLine, ex.Message, Environment.NewLine, ex.StackTrace), ex); + if (exceptionCount == filteredSourceDirectoryFiles.Length) + throw new Exception(string.Concat("All in [", sourceDirectory, "]failed!")); + } + }); + } + if (exceptionCount != 0) + throw new Exception(); + return (from l in results orderby Property.Models.Stateless.A_Property.GetMinimumDateTime(l.Property).Ticks select l).ToArray(); + } + + private void MoveFiles(string[] directories, List fromThenToCollection) + { + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + int z; + string to; + string from; + int moved = 0; + _Log.Information("Ready to move?"); + ConsoleKey? consoleKey = null; + for (int y = 0; y < int.MaxValue; y++) + { + _Log.Information("Press \"Y\" key when ready to continue"); + if (Console.ReadKey().Key == ConsoleKey.Y) + break; + } + _Log.Information(". . ."); + foreach (string directory in directories) + { + if (!Directory.Exists(directory)) + _ = Directory.CreateDirectory(directory); + } + z = 0; + foreach (string[] fromThenTo in fromThenToCollection) + { + z += 1; + from = fromThenTo[0]; + to = fromThenTo[1]; + if (z % 1000 == 0) + _Log.Information($"{z})"); + if (!File.Exists(from)) + continue; + if (File.Exists(to)) + continue; + File.Move(from, to); + moved += 1; + } + _Log.Information($"{moved} file(s) moved"); + for (int m = 0; m < int.MaxValue; m++) + { + moved = 0; + _Log.Information($"{m}) Ready to move back?"); + for (int y = 0; y < int.MaxValue; y++) + { + _Log.Information("Press \"Y\" key when ready to continue"); + if (Console.ReadKey().Key == ConsoleKey.Y) + break; + } + _Log.Information(". . ."); + z = 0; + foreach (string[] fromThenTo in fromThenToCollection) + { + z += 1; + from = fromThenTo[1]; + to = fromThenTo[0]; + if (z % 1000 == 0) + _Log.Information($"{z})"); + if (!File.Exists(from)) + continue; + if (File.Exists(to)) + continue; + File.Move(from, to); + moved += 1; + } + foreach (string directory in directories) + { + if (Directory.Exists(directory)) + { + if (!Directory.GetFiles(directory, "*", SearchOption.AllDirectories).Any()) + Directory.Delete(directory); + } + } + _Log.Information($"Done moving back {moved} file(s) for loop {m})"); + for (int y = 0; y < int.MaxValue; y++) + { + _Log.Information("Press \"Y\" key when ready to continue"); + _Log.Information("Press \"End\" key when ready to break"); + consoleKey = Console.ReadKey().Key; + if (consoleKey is ConsoleKey.Y or ConsoleKey.End) + break; + } + _Log.Information(". . ."); + if (consoleKey.HasValue && consoleKey == ConsoleKey.End) + break; + } + } + + public void SaveDiffFiles(string aPropertyCollectionDirectory, int loadLessThan, PropertyCompare[] propertyCompares, PropertyCompare[]? diffPropertyCompares) + { + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + string text; + string[] lines; + string fileName; + ConsoleKey? consoleKey = null; + List duplicateCollection; + for (int i = 0; i < loadLessThan; i++) + { + if (!propertyCompares.Any()) + continue; + if (diffPropertyCompares is null || !diffPropertyCompares.Any()) + duplicateCollection = GetDuplicates(propertyCompares, i, diffPropertyCompares); + else + { + if (i != 0) + { + if (diffPropertyCompares is null) + continue; + } + if (propertyCompares.Length == diffPropertyCompares.Length) + continue; + duplicateCollection = GetDuplicates(propertyCompares, i, diffPropertyCompares); + } + lines = (from l in duplicateCollection select l.GetSelect()).ToArray(); + _Log.Debug($"{i}) loop has {lines.Length} line(s)"); + if ((duplicateCollection.Count % 2) != 0) + continue; + fileName = Path.Join(aPropertyCollectionDirectory, $". . . {i}-Duplicates.txt"); + if (!duplicateCollection.Any()) + { + if (File.Exists(fileName)) + File.Delete(fileName); + continue; + } + text = string.Join(Environment.NewLine, lines); + File.WriteAllText(fileName, text); + for (int y = 0; y < int.MaxValue; y++) + { + _Log.Information("Press \"Y\" key when ready to continue"); + _Log.Information("Press \"End\" key when ready to break"); + consoleKey = Console.ReadKey().Key; + if (consoleKey is ConsoleKey.Y or ConsoleKey.End) + break; + } + _Log.Information(". . ."); + if (consoleKey.HasValue && consoleKey == ConsoleKey.End) + break; + } + } + + public void SaveLogAndMoveFiles(string aPropertyCollectionDirectory, int loadLessThan, PropertyCompare[] propertyCompares, PropertyCompare[]? diffPropertyCompares, int i) + { + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + List lines; + string checkDirectory; + string[] toDirectories; + ConsoleKey? consoleKey = null; + List fromThenToCollection; + _Log.Information($"{i}) example - number:{propertyCompares[0].Numbers[i]}; string:{propertyCompares[0].Strings[i]};"); + (toDirectories, fromThenToCollection) = Get(aPropertyCollectionDirectory, propertyCompares, i, diffPropertyCompares); + if (toDirectories.Length < 2) + _Log.Information($"{i}) loop only one directory :)"); + else + { + checkDirectory = toDirectories[1]; + _Log.Information($"{i}) loop {toDirectories.Length} directories and . . .{i}) - B will have ~{fromThenToCollection.Where(l => l[1].StartsWith(checkDirectory)).Count()}"); + } + for (int y = 0; y < int.MaxValue; y++) + { + _Log.Information($"Press \"Y\" key to {nameof(MoveFiles)} \"N\" to skip"); + consoleKey = Console.ReadKey().Key; + if (consoleKey is ConsoleKey.Y or ConsoleKey.N) + break; + } + _Log.Information(". . ."); + if (consoleKey.HasValue && consoleKey.Value == ConsoleKey.Y) + { + lines = new(); + foreach (string[] fromThenTo in fromThenToCollection) + { + lines.Add(fromThenTo[0]); + lines.Add(fromThenTo[1]); + } + File.WriteAllLines(Path.Join(aPropertyCollectionDirectory, $". . . {i}-All.txt"), lines); + MoveFiles(toDirectories, fromThenToCollection); + } + } + + public void WithSubdirectory(string propertyDirectory, bool subDirectoriesAny, string fileName, bool renameCompare, bool deleteArg) + { + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + List fileCollection = new(); + if (renameCompare && deleteArg) + throw new Exception(); + if (!renameCompare && !deleteArg) + throw new Exception(); + string[] lines; + string[] txtFiles = Directory.GetFiles(propertyDirectory, fileName, SearchOption.TopDirectoryOnly); + if (txtFiles.Length != 1) + lines = Array.Empty(); + else + lines = File.ReadAllLines(txtFiles[0]); + if (lines.Any()) + { + string argLine; + string moveFile; + string argFileName; + string compareLine; + string? argDirectory; + string argFullFileName; + string compareFileName; + string argDirectoryName; + string? compareDirectory; + string compareFullFileName; + string compareDirectoryName; + for (int i = 0; i < lines.Length; i++) + { + argLine = lines[i]; + compareLine = lines[i + 1]; + i += 1; + if (!subDirectoriesAny) + { + if (!argLine.StartsWith(_Configuration.RootDirectory) || !compareLine.StartsWith(_Configuration.RootDirectory)) + throw new Exception(i.ToString()); + } + else + { + if (!argLine.StartsWith(_Configuration.RootDirectory) || compareLine.StartsWith(_Configuration.RootDirectory)) + throw new Exception(i.ToString()); + } + } + for (int i = 0; i < lines.Length; i++) + { + argLine = lines[i]; + compareLine = lines[i + 1]; + i += 1; + if (!subDirectoriesAny) + { + if (!argLine.StartsWith(_Configuration.RootDirectory) || !compareLine.StartsWith(_Configuration.RootDirectory)) + throw new Exception(i.ToString()); + } + else + { + if (!argLine.StartsWith(_Configuration.RootDirectory) || compareLine.StartsWith(_Configuration.RootDirectory)) + throw new Exception(i.ToString()); + } + argFullFileName = argLine.Split('\t')[0]; + compareFullFileName = compareLine.Split('\t')[0]; + argFileName = Path.GetFileName(argFullFileName); + if (deleteArg) + { + if (!File.Exists(argFullFileName)) + continue; + fileCollection.Add(new string[] { argFullFileName }); + } + else if (renameCompare) + { + argDirectory = Path.GetDirectoryName(argFullFileName); + if (string.IsNullOrEmpty(argDirectory)) + continue; + compareDirectory = Path.GetDirectoryName(compareFullFileName); + if (string.IsNullOrEmpty(compareDirectory)) + continue; + argDirectoryName = Path.GetFileName(argDirectory); + if (argDirectoryName[..3].Equals(argFileName[..3], StringComparison.CurrentCultureIgnoreCase)) + continue; + compareDirectoryName = Path.GetFileName(argDirectory); + compareFileName = Path.GetFileName(compareFullFileName); + if (!compareDirectoryName[..3].Equals(compareFileName[..3], StringComparison.CurrentCultureIgnoreCase)) + continue; + if (!File.Exists(compareFullFileName)) + { + if (File.Exists(argFullFileName)) + fileCollection.Add(new string[] { argFullFileName }); + continue; + } + moveFile = Path.Combine(compareDirectory, argFileName); + if (File.Exists(moveFile)) + { + _Log.Information(argLine); + _Log.Information(compareLine); + continue; + } + fileCollection.Add(new string[] { compareFullFileName, moveFile }); + } + else + throw new Exception(); + } + } + foreach (string[] file in fileCollection) + { + if (deleteArg) + File.Delete(Path.GetFullPath(file[0])); + else if (renameCompare) + File.Move(Path.GetFullPath(file[0]), Path.GetFullPath(file[1])); + } + } + +} \ No newline at end of file diff --git a/Property-Compare/Models/Stateless/SerilogExtensionMethods.cs b/Property-Compare/Models/Stateless/SerilogExtensionMethods.cs new file mode 100644 index 0000000..955e16b --- /dev/null +++ b/Property-Compare/Models/Stateless/SerilogExtensionMethods.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.PropertyCompare.Models.Stateless; + +internal static class SerilogExtensionMethods +{ + + internal static void Warn(this Serilog.ILogger log, string messageTemplate) => log.Warning(messageTemplate); + + internal static void Info(this Serilog.ILogger log, string messageTemplate) => log.Information(messageTemplate); + +} \ No newline at end of file diff --git a/Property-Compare/Property-Compare.csproj b/Property-Compare/Property-Compare.csproj new file mode 100644 index 0000000..4c044a8 --- /dev/null +++ b/Property-Compare/Property-Compare.csproj @@ -0,0 +1,48 @@ + + + enable + 10.0 + enable + library + win-x64 + net6.0 + + + Phares.View.by.Distance.Property.Compare + false + 5.0.402.104 + Mike Phares + Phares + true + snupkg + + + true + true + true + + + Windows + + + OSX + + + Linux + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Property/.vscode/format-report.json b/Property/.vscode/format-report.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/Property/.vscode/format-report.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/Property/.vscode/settings.json b/Property/.vscode/settings.json new file mode 100644 index 0000000..0852522 --- /dev/null +++ b/Property/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "cSpell.words": [ + "dlib", + "Exif", + "nosj", + "Serilog" + ] +} \ No newline at end of file diff --git a/Property/Models/A_Property.cs b/Property/Models/A_Property.cs new file mode 100644 index 0000000..b2a1aaf --- /dev/null +++ b/Property/Models/A_Property.cs @@ -0,0 +1,123 @@ +using System.Text.Json; +using System.Text.Json.Serialization; +using View_by_Distance.Shared.Models.Methods; + +namespace View_by_Distance.Property.Models; + +/// +// A_Property +/// +public class A_Property : Shared.Models.Properties.IProperty, IProperty +{ + + protected DateTime _CreationTime; + protected DateTime? _DateTime; + protected DateTime? _DateTimeDigitized; + protected DateTime? _DateTimeOriginal; + protected long _FileSize; + protected DateTime? _GPSDateStamp; + protected int? _Height; + protected int? _Id; + protected int[] _Indices; + protected DateTime _LastWriteTime; + protected string _Make; + protected string _Model; + protected string _Orientation; + protected int? _Width; + public DateTime CreationTime => _CreationTime; + public DateTime? DateTime => _DateTime; + public DateTime? DateTimeDigitized => _DateTimeDigitized; + public DateTime? DateTimeOriginal => _DateTimeOriginal; + public long FileSize => _FileSize; + public DateTime? GPSDateStamp => _GPSDateStamp; + public int? Height => _Height; + public int? Id => _Id; + public int[] Indices => _Indices; + public DateTime LastWriteTime => _LastWriteTime; + public string Make => _Make; + public string Model => _Model; + public string Orientation => _Orientation; + public int? Width => _Width; + + [JsonConstructor] + public A_Property(DateTime creationTime, DateTime? dateTime, DateTime? dateTimeDigitized, DateTime? dateTimeOriginal, long fileSize, DateTime? gpsDateStamp, int? height, int? id, int[] indices, DateTime lastWriteTime, string make, string model, string orientation, int? width) + { + _CreationTime = creationTime; + _DateTime = dateTime; + _DateTimeDigitized = dateTimeDigitized; + _DateTimeOriginal = dateTimeOriginal; + _FileSize = fileSize; + _GPSDateStamp = gpsDateStamp; + _Height = height; + _Id = id; + _Indices = indices; + _LastWriteTime = lastWriteTime; + _Make = make; + _Model = model; + _Orientation = orientation; + _Width = width; + } + +#nullable disable + + public A_Property() + { + _CreationTime = System.DateTime.MinValue; + _DateTime = null; + _DateTimeDigitized = null; + _DateTimeOriginal = null; + _FileSize = long.MinValue; + _GPSDateStamp = null; + _Height = null; + _Id = null; + _Indices = Array.Empty(); + _LastWriteTime = System.DateTime.MinValue; + _Make = string.Empty; + _Model = string.Empty; + _Orientation = string.Empty; + _Width = null; + } + +#nullable restore + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + + public List GetDateTimes() => Stateless.A_Property.GetDateTimes(_CreationTime, _LastWriteTime, _DateTime, _DateTimeDigitized, _DateTimeOriginal, _GPSDateStamp); + + public (bool?, string[]) IsWrongYear(string filteredSourceDirectoryFile, DateTime? minimumDateTime) + { + string[] results = Array.Empty(); + bool? result = null; + string year; + string directoryName; + string[] directorySegments; + string? check = Path.GetPathRoot(filteredSourceDirectoryFile); + string? pathRoot = Path.GetPathRoot(filteredSourceDirectoryFile); + if (string.IsNullOrEmpty(pathRoot)) + throw new Exception(); + if (minimumDateTime.HasValue) + year = minimumDateTime.Value.ToString("yyyy"); + else + { + List datetimes = GetDateTimes(); + year = datetimes.Min().ToString("yyyy"); + } + for (int i = 0; i < int.MaxValue; i++) + { + check = Path.GetDirectoryName(check); + if (string.IsNullOrEmpty(check) || check == pathRoot) + break; + directoryName = Path.GetFileName(check); + directorySegments = directoryName.Split(' '); + (result, results) = Stateless.A_Property.IsWrongYear(directorySegments, year); + if (result.HasValue) + break; + } + return new(result, results); + } + +} \ No newline at end of file diff --git a/Property/Models/Binder/Configuration.cs b/Property/Models/Binder/Configuration.cs new file mode 100644 index 0000000..020b4ad --- /dev/null +++ b/Property/Models/Binder/Configuration.cs @@ -0,0 +1,48 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.Json; + +namespace View_by_Distance.Property.Models.Binder; + +public class Configuration +{ + + [Display(Name = "Date Group"), Required] public string DateGroup { get; set; } + [Display(Name = "File Name Directory Separator"), Required] public string FileNameDirectorySeparator { get; set; } + [Display(Name = "Force Property Last Write Time to Creation Time"), Required] public bool? ForcePropertyLastWriteTimeToCreationTime { get; set; } + [Display(Name = "Ignore Extensions"), Required] public string[] IgnoreExtensions { get; set; } + [Display(Name = "Max Images In Directory For Top Level First Pass"), Required] public int? MaxImagesInDirectoryForTopLevelFirstPass { get; set; } + [Display(Name = "Pattern"), Required] public string Pattern { get; set; } + [Display(Name = "Populate Properties Id"), Required] public bool? PopulatePropertyId { get; set; } + [Display(Name = "Properties Changed For Property"), Required] public bool? PropertiesChangedForProperty { get; set; } + [Display(Name = "Property Content Collection Files"), Required] public string[] PropertyContentCollectionFiles { get; set; } + [Display(Name = "Root Directory"), Required] public string RootDirectory { get; set; } + [Display(Name = "Valid Image Format Extensions"), Required] public string[] ValidImageFormatExtensions { get; set; } + [Display(Name = "Valid Metadata Extensions"), Required] public string[] ValidMetadataExtensions { get; set; } + [Display(Name = "Verify to Season"), Required] public string[] VerifyToSeason { get; set; } + [Display(Name = "Write Bitmap Data Bytes"), Required] public bool? WriteBitmapDataBytes { get; set; } + + public Configuration() + { + DateGroup = string.Empty; + FileNameDirectorySeparator = string.Empty; + ForcePropertyLastWriteTimeToCreationTime = null; + IgnoreExtensions = Array.Empty(); + MaxImagesInDirectoryForTopLevelFirstPass = null; + Pattern = string.Empty; + PopulatePropertyId = null; + PropertiesChangedForProperty = null; + PropertyContentCollectionFiles = Array.Empty(); + RootDirectory = string.Empty; + ValidImageFormatExtensions = Array.Empty(); + ValidMetadataExtensions = Array.Empty(); + VerifyToSeason = Array.Empty(); + WriteBitmapDataBytes = null; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/Property/Models/Configuration.cs b/Property/Models/Configuration.cs new file mode 100644 index 0000000..f31252b --- /dev/null +++ b/Property/Models/Configuration.cs @@ -0,0 +1,101 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Property.Models; + +public class Configuration +{ + + protected readonly string _DateGroup; + protected readonly string _FileNameDirectorySeparator; + protected readonly bool? _ForcePropertyLastWriteTimeToCreationTime; + protected readonly string[] _IgnoreExtensions; + protected readonly int? _MaxImagesInDirectoryForTopLevelFirstPass; + protected readonly string _Pattern; + protected readonly bool? _PopulatePropertyId; + protected readonly bool? _PropertiesChangedForProperty; + protected readonly string[] _PropertyContentCollectionFiles; + protected string _RootDirectory; + protected readonly string[] _ValidImageFormatExtensions; + protected readonly string[] _ValidMetadataExtensions; + protected readonly string[] _VerifyToSeason; + protected readonly bool? _WriteBitmapDataBytes; + public string DateGroup => _DateGroup; + public string FileNameDirectorySeparator => _FileNameDirectorySeparator; + public bool? ForcePropertyLastWriteTimeToCreationTime => _ForcePropertyLastWriteTimeToCreationTime; + public string[] IgnoreExtensions => _IgnoreExtensions; + public int? MaxImagesInDirectoryForTopLevelFirstPass => _MaxImagesInDirectoryForTopLevelFirstPass; + public string Pattern => _Pattern; + public bool? PopulatePropertyId => _PopulatePropertyId; + public bool? PropertiesChangedForProperty => _PropertiesChangedForProperty; + public string[] PropertyContentCollectionFiles => _PropertyContentCollectionFiles; + public string RootDirectory => _RootDirectory; + public string[] ValidImageFormatExtensions => _ValidImageFormatExtensions; + public string[] ValidMetadataExtensions => _ValidMetadataExtensions; + public string[] VerifyToSeason => _VerifyToSeason; + public bool? WriteBitmapDataBytes => _WriteBitmapDataBytes; + + [JsonConstructor] + public Configuration(string dateGroup, string fileNameDirectorySeparator, bool? forcePropertyLastWriteTimeToCreationTime, string[] ignoreExtensions, int? maxImagesInDirectoryForTopLevelFirstPass, string pattern, bool? populatePropertyId, bool? propertiesChangedForProperty, string[] propertyContentCollectionFiles, string rootDirectory, string[] validImageFormatExtensions, string[] validMetadataExtensions, string[] verifyToSeason, bool? writeBitmapDataBytes) + { + _DateGroup = dateGroup; + _FileNameDirectorySeparator = fileNameDirectorySeparator; + _ForcePropertyLastWriteTimeToCreationTime = forcePropertyLastWriteTimeToCreationTime; + _IgnoreExtensions = ignoreExtensions; + _MaxImagesInDirectoryForTopLevelFirstPass = maxImagesInDirectoryForTopLevelFirstPass; + _Pattern = pattern; + _PopulatePropertyId = populatePropertyId; + _PropertiesChangedForProperty = propertiesChangedForProperty; + _PropertyContentCollectionFiles = propertyContentCollectionFiles; + _RootDirectory = rootDirectory; + _ValidImageFormatExtensions = validImageFormatExtensions; + _ValidMetadataExtensions = validMetadataExtensions; + _VerifyToSeason = verifyToSeason; + _WriteBitmapDataBytes = writeBitmapDataBytes; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + + public void Update() => _RootDirectory = Path.GetFullPath(_RootDirectory); + + public static void Verify(Configuration? propertyConfiguration) + { + if (propertyConfiguration is null) + throw new Exception($"{nameof(propertyConfiguration)} must be set!"); + if (propertyConfiguration.ForcePropertyLastWriteTimeToCreationTime is null) + throw new Exception($"{nameof(propertyConfiguration.ForcePropertyLastWriteTimeToCreationTime)} must be set!"); + if (propertyConfiguration.IgnoreExtensions is null || !propertyConfiguration.IgnoreExtensions.Any()) + throw new Exception($"{nameof(propertyConfiguration.IgnoreExtensions)} must be set!"); + if (propertyConfiguration.PopulatePropertyId is null) + throw new Exception($"{nameof(propertyConfiguration.PopulatePropertyId)} must be set!"); + if (propertyConfiguration.PropertiesChangedForProperty is null) + throw new Exception($"{nameof(propertyConfiguration.PropertiesChangedForProperty)} must be set!"); + if (propertyConfiguration.PropertyContentCollectionFiles is null) + throw new Exception($"{nameof(propertyConfiguration.PropertyContentCollectionFiles)} must be set!"); + if (propertyConfiguration.ValidImageFormatExtensions is null || !propertyConfiguration.ValidImageFormatExtensions.Any()) + throw new Exception($"{nameof(propertyConfiguration.ValidImageFormatExtensions)} must be set!"); + if (propertyConfiguration.ValidMetadataExtensions is null || !propertyConfiguration.ValidMetadataExtensions.Any()) + throw new Exception($"{nameof(propertyConfiguration.ValidMetadataExtensions)} must be set!"); + if (propertyConfiguration.VerifyToSeason is null || !propertyConfiguration.VerifyToSeason.Any()) + throw new Exception($"{nameof(propertyConfiguration.VerifyToSeason)} must be set!"); + if (propertyConfiguration.WriteBitmapDataBytes is null) + throw new Exception($"{nameof(propertyConfiguration.WriteBitmapDataBytes)} must be set!"); + if (Path.GetPathRoot(propertyConfiguration.RootDirectory) == propertyConfiguration.RootDirectory) + throw new Exception($"{nameof(propertyConfiguration.RootDirectory)} should have at least one level!"); + if (propertyConfiguration is null) + throw new Exception($"{nameof(propertyConfiguration)} must be set!"); + if (string.IsNullOrEmpty(propertyConfiguration.DateGroup)) + throw new Exception($"{nameof(propertyConfiguration.DateGroup)} must have a value!"); + if (string.IsNullOrEmpty(propertyConfiguration.FileNameDirectorySeparator)) + throw new Exception($"{nameof(propertyConfiguration.FileNameDirectorySeparator)} must have a value!"); + if (string.IsNullOrEmpty(propertyConfiguration.Pattern)) + throw new Exception($"{nameof(propertyConfiguration.Pattern)} must have a value!"); + if (string.IsNullOrEmpty(propertyConfiguration.RootDirectory) || !Directory.Exists(propertyConfiguration.RootDirectory)) + throw new Exception($"{nameof(propertyConfiguration.RootDirectory)} must have a value and exits!"); + } + +} \ No newline at end of file diff --git a/Property/Models/Group.cs b/Property/Models/Group.cs new file mode 100644 index 0000000..fbf817e --- /dev/null +++ b/Property/Models/Group.cs @@ -0,0 +1,32 @@ +namespace View_by_Distance.Property.Models; + +public class Group +{ + + protected readonly int _G; + protected readonly string _SourceDirectory; + protected readonly string[] _FilteredSourceDirectoryFiles; + protected readonly int _R; + protected readonly bool[] _ValidImageFormatExtentionCollection; + protected readonly FileInfo?[] _PropertyFileInfoCollection; + protected readonly A_Property?[] _PropertyCollection; + public int G => _G; + public string SourceDirectory => _SourceDirectory; + public string[] FilteredSourceDirectoryFiles => _FilteredSourceDirectoryFiles; + public int R => _R; + public bool[] ValidImageFormatExtentionCollection => _ValidImageFormatExtentionCollection; + public FileInfo?[] PropertyFileInfoCollection => _PropertyFileInfoCollection; + public A_Property?[] PropertyCollection => _PropertyCollection; + + public Group(int g, string sourceDirectory, string[] filteredSourceDirectoryFiles, int r) + { + _G = g; + _SourceDirectory = sourceDirectory; + _FilteredSourceDirectoryFiles = filteredSourceDirectoryFiles; + _R = r; + _ValidImageFormatExtentionCollection = Enumerable.Repeat(false, filteredSourceDirectoryFiles.Length).ToArray(); + _PropertyFileInfoCollection = Enumerable.Repeat(null, filteredSourceDirectoryFiles.Length).ToArray(); + _PropertyCollection = Enumerable.Repeat(null, filteredSourceDirectoryFiles.Length).ToArray(); + } + +} \ No newline at end of file diff --git a/Property/Models/PropertyLogic.cs b/Property/Models/PropertyLogic.cs new file mode 100644 index 0000000..fc789ff --- /dev/null +++ b/Property/Models/PropertyLogic.cs @@ -0,0 +1,780 @@ +using ShellProgressBar; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Imaging; +using System.Globalization; +using System.Runtime.InteropServices; +using System.Text; +using System.Text.Json; +using View_by_Distance.Property.Models.Stateless; +using View_by_Distance.Shared.Models.Stateless; + +namespace View_by_Distance.Property.Models; + +public class PropertyLogic +{ + + protected readonly Dictionary _IndicesFromNew; + protected readonly Dictionary _IndicesFromOld; + + public List AngleBracketCollection { get; } + public Dictionary IndicesFromNew => _IndicesFromNew; + public Dictionary IndicesFromOld => _IndicesFromOld; + + private readonly Serilog.ILogger? _Log; + private readonly string[] _VerifyToSeason; + private readonly int _MaxDegreeOfParallelism; + private readonly ASCIIEncoding _ASCIIEncoding; + private readonly Configuration _Configuration; + private readonly List _ExceptionsDirectories; + private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions; + + public PropertyLogic(int maxDegreeOfParallelism, Configuration configuration, string[] verifyToSeason) + { + _Configuration = configuration; + _ExceptionsDirectories = new(); + _VerifyToSeason = verifyToSeason; + _ASCIIEncoding = new ASCIIEncoding(); + AngleBracketCollection = new List(); + _Log = Serilog.Log.ForContext(); + _MaxDegreeOfParallelism = maxDegreeOfParallelism; + _WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true }; + if (verifyToSeason is null) + throw new Exception(); + string json; + string fullPath; + Dictionary? indicesFromOld; + List>? collection; + Dictionary indicesFromNew = new(); + string? rootDirectoryParent = Path.GetDirectoryName(configuration.RootDirectory); + if (string.IsNullOrEmpty(rootDirectoryParent)) + throw new Exception($"{nameof(rootDirectoryParent)} is null!"); + string keyValuePairsJsonFile = Path.Combine(rootDirectoryParent, "keyValuePairs-637864726339738801.json"); + if (!File.Exists(keyValuePairsJsonFile)) + indicesFromOld = new(); + else + { + json = File.ReadAllText(keyValuePairsJsonFile); + indicesFromOld = JsonSerializer.Deserialize>(json); + if (indicesFromOld is null) + throw new Exception($"{nameof(indicesFromOld)} is null!"); + } + foreach (string propertyContentCollectionFile in configuration.PropertyContentCollectionFiles) + { + fullPath = Path.GetFullPath(string.Concat(rootDirectoryParent, propertyContentCollectionFile)); + if (fullPath.Contains(configuration.RootDirectory)) + continue; + if (!File.Exists(fullPath)) + continue; + json = File.ReadAllText(fullPath); + collection = JsonSerializer.Deserialize>>(json); + if (collection is null) + throw new Exception($"{nameof(collection)} is null!"); + foreach (KeyValuePair keyValuePair in collection) + { + if (indicesFromNew.ContainsKey(keyValuePair.Key)) + continue; + indicesFromNew.Add(keyValuePair.Key, keyValuePair.Value); + } + } + _IndicesFromNew = indicesFromNew; + _IndicesFromOld = indicesFromOld; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + + private long LogDelta(long ticks, string methodName) + { + long result; + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + double delta = new TimeSpan(DateTime.Now.Ticks - ticks).TotalMilliseconds; + _Log.Debug($"{methodName} took {Math.Floor(delta)} millisecond(s)"); + result = DateTime.Now.Ticks; + return result; + } + + public static List GetMetadataDateTimesByPattern(string dateTimeFormat, string filteredSourceDirectoryFile) + { + List results = new(); + try + { + DateTime checkDateTime; + DateTime kristy = new(1976, 3, 8); + IReadOnlyList directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(filteredSourceDirectoryFile); + foreach (MetadataExtractor.Directory directory in directories) + { + foreach (MetadataExtractor.Tag tag in directory.Tags) + { + if (string.IsNullOrEmpty(tag.Description) || tag.Description.Length != dateTimeFormat.Length) + continue; + if (!DateTime.TryParseExact(tag.Description, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out checkDateTime)) + continue; + if (checkDateTime < kristy) + continue; + results.Add(checkDateTime); + } + } + } + catch (Exception) { } + return results; + } + +#pragma warning disable CA1416 + + private A_Property GetImageProperty(string angleBracket, string filteredSourceDirectoryFile, bool populateId, bool isIgnoreExtension, bool isValidImageFormatExtension, bool isValidMetadataExtensions, int? id, List indices) + { + A_Property result; + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + if (_Configuration.WriteBitmapDataBytes is null) + throw new Exception($"{nameof(_Configuration.WriteBitmapDataBytes)} is null!"); + long ticks; + byte[] bytes; + string value; + int encodingHash; + int? width = null; + int? height = null; + string dateTimeFormat; + DateTime checkDateTime; + DateTime? dateTime = null; + PropertyItem? propertyItem; + string make = string.Empty; + string model = string.Empty; + DateTime? gpsDateStamp = null; + DateTime? dateTimeOriginal = null; + string orientation = string.Empty; + DateTime? dateTimeDigitized = null; + FileInfo fileInfo = new(filteredSourceDirectoryFile); + long fileInfoLength = fileInfo.Length; + DateTime creationTime = fileInfo.CreationTime; + DateTime lastWriteTime = fileInfo.LastWriteTime; + if (isValidMetadataExtensions) + { + dateTimeFormat = "ddd MMM dd HH:mm:ss yyyy"; + List dateTimes = GetMetadataDateTimesByPattern(dateTimeFormat, filteredSourceDirectoryFile); + if (dateTimes.Any()) + dateTimeOriginal = dateTimes.Min(); + } + else if (!isIgnoreExtension && isValidImageFormatExtension) + { + try + { + using Image image = Image.FromFile(filteredSourceDirectoryFile); + if (populateId && (id is null || !indices.Any())) + { + using Bitmap bitmap = new(image); + Rectangle rectangle = new(0, 0, image.Width, image.Height); + BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, bitmap.PixelFormat); + IntPtr intPtr = bitmapData.Scan0; + int length = bitmapData.Stride * bitmap.Height; + bytes = new byte[length]; + Marshal.Copy(intPtr, bytes, 0, length); + bitmap.UnlockBits(bitmapData); + if (id is null) + { + ticks = DateTime.Now.Ticks; + id = Stateless.A_Property.GetDeterministicHashCode(bytes); + if (_MaxDegreeOfParallelism < 2) + ticks = LogDelta(ticks, nameof(Stateless.A_Property.GetDeterministicHashCode)); + } + if (_Configuration.WriteBitmapDataBytes.Value) + { + FileInfo contentFileInfo = new(Path.Combine(angleBracket.Replace("<>", "()"), Path.GetFileName(filteredSourceDirectoryFile))); + File.WriteAllBytes(Path.ChangeExtension(contentFileInfo.FullName, string.Empty), bytes); + } + if (_IndicesFromNew.ContainsKey(id.Value) && _IndicesFromNew[id.Value].Any()) + indices.AddRange(_IndicesFromNew[id.Value]); + else + { + ticks = DateTime.Now.Ticks; + string encoding = Encoding.Default.GetString(bytes); + if (_MaxDegreeOfParallelism < 2) + ticks = LogDelta(ticks, nameof(Encoding.Default.GetString)); + encodingHash = Stateless.A_Property.GetDeterministicHashCode(encoding); + if (_MaxDegreeOfParallelism < 2) + ticks = LogDelta(ticks, nameof(Stateless.A_Property.GetDeterministicHashCode)); + if (!_IndicesFromOld.ContainsKey(encodingHash)) + indices.Add(encodingHash); + else + indices.AddRange(_IndicesFromOld[encodingHash]); + } + } + width = image.Width; + height = image.Height; + dateTimeFormat = Stateless.A_Property.DateTimeFormat(); + if (image.PropertyIdList.Contains((int)IExif.Tags.DateTime)) + { + propertyItem = image.GetPropertyItem((int)IExif.Tags.DateTime); + if (propertyItem?.Value is not null) + { + value = _ASCIIEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); + if (value.Length > dateTimeFormat.Length) + value = value[..dateTimeFormat.Length]; + if (value.Length == dateTimeFormat.Length && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out checkDateTime)) + dateTime = checkDateTime; + } + } + if (image.PropertyIdList.Contains((int)IExif.Tags.DateTimeDigitized)) + { + propertyItem = image.GetPropertyItem((int)IExif.Tags.DateTimeDigitized); + if (propertyItem?.Value is not null) + { + value = _ASCIIEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); + if (value.Length > dateTimeFormat.Length) + value = value[..dateTimeFormat.Length]; + if (value.Length == dateTimeFormat.Length && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out checkDateTime)) + dateTimeDigitized = checkDateTime; + } + } + if (image.PropertyIdList.Contains((int)IExif.Tags.DateTimeOriginal)) + { + propertyItem = image.GetPropertyItem((int)IExif.Tags.DateTimeOriginal); + if (propertyItem?.Value is not null) + { + value = _ASCIIEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); + if (value.Length > dateTimeFormat.Length) + value = value[..dateTimeFormat.Length]; + if (value.Length == dateTimeFormat.Length && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out checkDateTime)) + dateTimeOriginal = checkDateTime; + } + } + if (image.PropertyIdList.Contains((int)IExif.Tags.GPSDateStamp)) + { + propertyItem = image.GetPropertyItem((int)IExif.Tags.GPSDateStamp); + if (propertyItem?.Value is not null) + { + value = _ASCIIEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); + if (value.Length > dateTimeFormat.Length) + value = value[..dateTimeFormat.Length]; + if (value.Length == dateTimeFormat.Length && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out checkDateTime)) + gpsDateStamp = checkDateTime; + } + } + if (image.PropertyIdList.Contains((int)IExif.Tags.Make)) + { + propertyItem = image.GetPropertyItem((int)IExif.Tags.Make); + if (propertyItem?.Value is not null) + { + value = _ASCIIEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); + make = value; + } + } + if (image.PropertyIdList.Contains((int)IExif.Tags.Model)) + { + propertyItem = image.GetPropertyItem((int)IExif.Tags.Model); + if (propertyItem?.Value is not null) + { + value = _ASCIIEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); + model = value; + } + } + if (image.PropertyIdList.Contains((int)IExif.Tags.Orientation)) + { + propertyItem = image.GetPropertyItem((int)IExif.Tags.Orientation); + if (propertyItem?.Value is not null) + { + value = BitConverter.ToInt16(propertyItem.Value, 0).ToString(); + orientation = value; + } + } + } + catch (Exception) + { + _Log.Info(string.Concat(new StackFrame().GetMethod()?.Name, " <", filteredSourceDirectoryFile, ">")); + } + } + else + dateTimeOriginal = null; + result = new(creationTime, dateTime, dateTimeDigitized, dateTimeOriginal, fileInfoLength, gpsDateStamp, height, id, indices.ToArray(), lastWriteTime, make, model, orientation, width); + return result; + } + +#pragma warning restore CA1416 + + private A_Property GetProperty(List> filteredSourceDirectoryFileTuples, List parseExceptions, bool firstPass, string angleBracket, string filteredSourceDirectoryFile, FileInfo fileInfo, bool isIgnoreExtension, bool isValidImageFormatExtension, bool isValidMetadataExtensions) + { + A_Property? result; + if (_Configuration.ForcePropertyLastWriteTimeToCreationTime is null) + throw new Exception($"{nameof(_Configuration.ForcePropertyLastWriteTimeToCreationTime)} is null!"); + if (_Configuration.PopulatePropertyId is null) + throw new Exception($"{nameof(_Configuration.PopulatePropertyId)} is null!"); + if (_Configuration.PropertiesChangedForProperty is null) + throw new Exception($"{nameof(_Configuration.PropertiesChangedForProperty)} is null!"); + string json; + int? id = null; + List indices = new(); + bool hasWrongYearProperty = false; + string[] changesFrom = new string[] { "B_Metadata" }; + bool populateId = !firstPass && _Configuration.PopulatePropertyId.Value; + List dateTimes = (from l in filteredSourceDirectoryFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); + if (!fileInfo.Exists) + { + if (fileInfo.Directory?.Parent is null) + throw new Exception(); + string parentCheck = Path.Combine(fileInfo.Directory.Parent.FullName, fileInfo.Name); + if (File.Exists(parentCheck)) + { + File.Move(parentCheck, fileInfo.FullName); + fileInfo.Refresh(); + } + } + if (_Configuration.ForcePropertyLastWriteTimeToCreationTime.Value && !fileInfo.Exists && File.Exists(Path.ChangeExtension(fileInfo.FullName, ".delete"))) + { + File.Move(Path.ChangeExtension(fileInfo.FullName, ".delete"), fileInfo.FullName); + fileInfo.Refresh(); + } + if (_Configuration.ForcePropertyLastWriteTimeToCreationTime.Value && fileInfo.Exists && fileInfo.LastWriteTime != fileInfo.CreationTime) + { + File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime); + fileInfo.Refresh(); + } + if (_Configuration.PropertiesChangedForProperty.Value) + result = null; + else if (!fileInfo.Exists) + result = null; + else if (dateTimes.Any() && dateTimes.Max() > fileInfo.LastWriteTime) + result = null; + else + { + json = File.ReadAllText(fileInfo.FullName); + try + { + bool check = true; + A_Property? property = JsonSerializer.Deserialize(json); + if (!isIgnoreExtension && isValidImageFormatExtension && ((populateId && property?.Id is null) || property?.Width is null || property?.Height is null)) + { + check = false; + id = property?.Id; + if (property is not null && property.Indices.Any()) + indices = property.Indices.ToList(); + property = GetImageProperty(angleBracket, filteredSourceDirectoryFile, populateId, isIgnoreExtension, isValidImageFormatExtension, isValidMetadataExtensions, id, indices); + } + if (!isIgnoreExtension && isValidImageFormatExtension && populateId && property is not null && !property.Indices.Any()) + { + check = false; + id = property?.Id; + if (property is not null && property.Indices.Any()) + indices = property.Indices.ToList(); + property = GetImageProperty(angleBracket, filteredSourceDirectoryFile, populateId, isIgnoreExtension, isValidImageFormatExtension, isValidMetadataExtensions, id, indices); + } + if (!isIgnoreExtension && isValidImageFormatExtension && populateId && property is not null && property.LastWriteTime != new FileInfo(filteredSourceDirectoryFile).LastWriteTime) + { + check = false; + id = null; + indices.Clear(); + property = GetImageProperty(angleBracket, filteredSourceDirectoryFile, populateId, isIgnoreExtension, isValidImageFormatExtension, isValidMetadataExtensions, id, indices); + } + if (!isIgnoreExtension && isValidImageFormatExtension && property?.Width is not null && property?.Height is not null && property.Width.Value == property.Height.Value && File.Exists(filteredSourceDirectoryFile)) + { + check = false; + id = property?.Id; + if (property is not null && property.Indices.Any()) + indices = property.Indices.ToList(); + property = GetImageProperty(angleBracket, filteredSourceDirectoryFile, populateId, isIgnoreExtension, isValidImageFormatExtension, isValidMetadataExtensions, id, indices); + if (property?.Width is not null && property?.Height is not null && property.Width.Value != property.Height.Value) + throw new Exception("Was square!"); + } + if (json.Contains("WrongYear")) + { + id = property?.Id; + hasWrongYearProperty = true; + } + if (property is null) + throw new Exception(); + if (!check) + result = null; + else + { + result = property; + filteredSourceDirectoryFileTuples.Add(new Tuple(nameof(A_Property), fileInfo.LastWriteTime)); + } + } + catch (Exception) + { + result = null; + parseExceptions.Add(nameof(A_Property)); + } + } + if (result is null) + { + result = GetImageProperty(angleBracket, filteredSourceDirectoryFile, populateId, isIgnoreExtension, isValidImageFormatExtension, isValidMetadataExtensions, id, indices); + json = JsonSerializer.Serialize(result, _WriteIndentedJsonSerializerOptions); + if (populateId && IPath.WriteAllText(fileInfo.FullName, json, compareBeforeWrite: true)) + { + if (!_Configuration.ForcePropertyLastWriteTimeToCreationTime.Value && (!fileInfo.Exists || fileInfo.LastWriteTime == fileInfo.CreationTime)) + filteredSourceDirectoryFileTuples.Add(new Tuple(nameof(A_Property), DateTime.Now)); + else + { + File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime); + fileInfo.Refresh(); + filteredSourceDirectoryFileTuples.Add(new Tuple(nameof(A_Property), fileInfo.CreationTime)); + } + } + } + else if (hasWrongYearProperty) + { + json = JsonSerializer.Serialize(result, _WriteIndentedJsonSerializerOptions); + if (IPath.WriteAllText(fileInfo.FullName, json, compareBeforeWrite: true)) + { + File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime); + fileInfo.Refresh(); + filteredSourceDirectoryFileTuples.Add(new Tuple(nameof(A_Property), fileInfo.CreationTime)); + } + } + return result; + } + + private bool AnyFilesMoved(Group group) + { + bool result = false; + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + int season; + string[] matches; + string deleteFile; + bool? isWrongYear; + string seasonName; + DateTime dateTime; + A_Property? property; + string destinationFile; + DateTime minimumDateTime; + FileInfo? propertyFileInfo; + string destinationDirectory; + string[] sourceDirectorySegments; + string filteredSourceDirectoryFile; + FileInfo filteredSourceDirectoryFileInfo; + DateTime directoryMaximumOfMinimumDateTime = DateTime.MinValue; + for (int i = 0; i < group.FilteredSourceDirectoryFiles.Length; i++) + { + if (!group.ValidImageFormatExtentionCollection[i]) + continue; + property = group.PropertyCollection[i]; + if (property is null) + continue; + minimumDateTime = Stateless.A_Property.GetMinimumDateTime(property); + if (minimumDateTime > directoryMaximumOfMinimumDateTime) + directoryMaximumOfMinimumDateTime = minimumDateTime; + filteredSourceDirectoryFile = group.FilteredSourceDirectoryFiles[i]; + filteredSourceDirectoryFileInfo = new(filteredSourceDirectoryFile); + if (minimumDateTime != filteredSourceDirectoryFileInfo.CreationTime) + { + (isWrongYear, matches) = property.IsWrongYear(filteredSourceDirectoryFile, minimumDateTime); + if (isWrongYear is null || !isWrongYear.Value) + dateTime = minimumDateTime; + else + { + if (isWrongYear.HasValue && isWrongYear.Value) + _Log.Information($"Wrong Year? <{filteredSourceDirectoryFile}>"); + if (!matches.Any()) + continue; + if (!DateTime.TryParseExact(matches[0], "yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) + continue; + } + try + { File.SetCreationTime(filteredSourceDirectoryFile, dateTime); } + catch (Exception) + { } + } + if (!_VerifyToSeason.Contains(group.SourceDirectory)) + continue; + propertyFileInfo = group.PropertyFileInfoCollection[i]; + if (propertyFileInfo is null) + continue; + sourceDirectorySegments = Path.GetFileName(group.SourceDirectory).Split(' '); + (season, seasonName) = Stateless.A_Property.GetSeason(minimumDateTime.DayOfYear); + if (sourceDirectorySegments[0] == "zzz") + destinationDirectory = Path.Combine(_Configuration.RootDirectory, $"zzz ={minimumDateTime:yyyy}.{season} {seasonName} {string.Join(' ', sourceDirectorySegments.Skip(3))}"); + else if (sourceDirectorySegments.Length > 2) + destinationDirectory = Path.Combine(_Configuration.RootDirectory, $"={minimumDateTime:yyyy}.{season} {seasonName} {string.Join(' ', sourceDirectorySegments.Skip(2))}"); + else + destinationDirectory = Path.Combine(_Configuration.RootDirectory, $"={minimumDateTime:yyyy}.{season} {seasonName}"); + if (destinationDirectory == group.SourceDirectory) + continue; + if (!result) + result = true; + if (!Directory.Exists(destinationDirectory)) + _ = Directory.CreateDirectory(destinationDirectory); + destinationFile = Path.Combine(destinationDirectory, filteredSourceDirectoryFileInfo.Name); + if (File.Exists(destinationFile)) + { + if (destinationFile.EndsWith(".jpg", ignoreCase: true, CultureInfo.CurrentCulture)) + destinationFile = Path.Combine(destinationDirectory, Path.ChangeExtension(filteredSourceDirectoryFileInfo.Name, ".jpeg")); + else if (destinationFile.EndsWith(".jpeg", ignoreCase: true, CultureInfo.CurrentCulture)) + destinationFile = Path.Combine(destinationDirectory, Path.ChangeExtension(filteredSourceDirectoryFileInfo.Name, ".jpg")); + } + if (File.Exists(destinationFile)) + { + _Log.Information($"*** source <{filteredSourceDirectoryFile}>"); + _Log.Information($"*** destination <{destinationFile}>"); + if (propertyFileInfo.Exists) + { + deleteFile = Path.ChangeExtension(propertyFileInfo.FullName, ".delete"); + if (File.Exists(deleteFile)) + File.Delete(deleteFile); + File.Move(propertyFileInfo.FullName, deleteFile); + } + } + else + { + File.Move(filteredSourceDirectoryFile, destinationFile); + if (propertyFileInfo.Exists) + { + deleteFile = Path.ChangeExtension(propertyFileInfo.FullName, ".delete"); + if (File.Exists(deleteFile)) + File.Delete(deleteFile); + File.Move(propertyFileInfo.FullName, deleteFile); + } + } + } + if (directoryMaximumOfMinimumDateTime != DateTime.MinValue) + { + DirectoryInfo directoryInfo = new(group.SourceDirectory); + if (directoryInfo.LastWriteTime != directoryMaximumOfMinimumDateTime) + Directory.SetLastWriteTime(group.SourceDirectory, directoryMaximumOfMinimumDateTime); + } + return result; + } + + private void WriteGroup(Group group, string angleBracket) + { + if (!(from l in @group.PropertyCollection where l?.Width is null select true).Any()) + { + string key; + string json; + string checkFile; + A_Property? property; + string checkDirectory; + int sourceDirectoryLength = group.SourceDirectory.Length; + List> propertyCollectionKeyValuePairs = new(); + JsonSerializerOptions writeIndentedJsonSerializerOptions = new() { WriteIndented = false }; + (int level, List directories) = IPath.Get(_Configuration.RootDirectory, group.SourceDirectory); + string fileName = string.Concat(string.Join(_Configuration.FileNameDirectorySeparator, directories), ".json"); + for (int i = 0; i < group.FilteredSourceDirectoryFiles.Length; i++) + { + property = group.PropertyCollection[i]; + if (property is null) + continue; + key = IPath.GetRelativePath(group.FilteredSourceDirectoryFiles[i], sourceDirectoryLength); + propertyCollectionKeyValuePairs.Add(new KeyValuePair(key, property)); + } + checkDirectory = IPath.GetDirectory(angleBracket, level, "[{}]"); + checkFile = Path.Combine(checkDirectory, fileName); + if (File.Exists(checkFile)) + File.Move(checkFile, Path.Combine(checkDirectory, fileName)); + checkFile = Path.Combine(checkDirectory, fileName); + json = JsonSerializer.Serialize(propertyCollectionKeyValuePairs, writeIndentedJsonSerializerOptions); + _ = IPath.WriteAllText(checkFile, json, compareBeforeWrite: true); + } + } + + private (List> filteredSourceDirectoryFileTuples, bool isValidImageFormatExtension, FileInfo propertyFileInfo, A_Property property) ParallelForWork(bool firstPass, string angleBracket, string sourceDirectory, string filteredSourceDirectoryFile) + { + List parseExceptions = new(); + List> filteredSourceDirectoryFileTuples = new(); + string extensionLowered = Path.GetExtension(filteredSourceDirectoryFile).ToLower(); + bool isValidMetadataExtensions = _Configuration.ValidMetadataExtensions.Contains(extensionLowered); + bool isValidImageFormatExtension = _Configuration.ValidImageFormatExtensions.Contains(extensionLowered); + bool isIgnoreExtension = isValidImageFormatExtension && _Configuration.IgnoreExtensions.Contains(extensionLowered); + string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(filteredSourceDirectoryFile); + string filteredSourceDirectoryFileExtensionLowered = Path.Combine(sourceDirectory, $"{fileNameWithoutExtension}{extensionLowered}"); + if (isValidImageFormatExtension && filteredSourceDirectoryFile.Length == filteredSourceDirectoryFileExtensionLowered.Length && filteredSourceDirectoryFile != filteredSourceDirectoryFileExtensionLowered) + File.Move(filteredSourceDirectoryFile, filteredSourceDirectoryFileExtensionLowered); + string without = Path.Combine(angleBracket.Replace("<>", "{}"), $"{fileNameWithoutExtension}.json"); + FileInfo propertyFileInfo = new(Path.Combine(angleBracket.Replace("<>", "{}"), $"{fileNameWithoutExtension}{extensionLowered}.json")); + if (isValidImageFormatExtension && File.Exists(without)) + { + File.Move(without, propertyFileInfo.FullName); + propertyFileInfo.Refresh(); + } + A_Property property = GetProperty(filteredSourceDirectoryFileTuples, parseExceptions, firstPass, angleBracket, filteredSourceDirectoryFile, propertyFileInfo, isIgnoreExtension, isValidImageFormatExtension, isValidMetadataExtensions); + return new(filteredSourceDirectoryFileTuples, isValidImageFormatExtension, propertyFileInfo, property); + } + + private int ParallelWork(bool firstPass, object @lock, long ticks, List> sourceDirectoryChanges, int count, Group group, string angleBracket) + { + int result = 0; + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = _MaxDegreeOfParallelism }; + int totalSeconds = (int)Math.Truncate(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); + ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; + using (ProgressBar progressBar = new(group.FilteredSourceDirectoryFiles.Length, $"{group.G}) {group.R + 1:000} / {count:000} - {group.SourceDirectory} - {group.FilteredSourceDirectoryFiles.Length} file(s) - {totalSeconds} total second(s)", options)) + { + _ = Parallel.For(0, group.FilteredSourceDirectoryFiles.Length, parallelOptions, i => + { + try + { + long ticks = DateTime.Now.Ticks; + DateTime dateTime = DateTime.Now; + (List> filteredSourceDirectoryFileTuples, bool isValidImageFormatExtension, FileInfo propertyFileInfo, A_Property property) = ParallelForWork(firstPass, angleBracket, group.SourceDirectory, group.FilteredSourceDirectoryFiles[i]); + progressBar.Tick(); + if (_MaxDegreeOfParallelism < 2) + ticks = LogDelta(ticks, nameof(PropertyLogic.ParallelForWork)); + lock (@lock) + { + group.PropertyCollection[i] = property; + group.PropertyFileInfoCollection[i] = propertyFileInfo; + if (isValidImageFormatExtension) + group.ValidImageFormatExtentionCollection[i] = isValidImageFormatExtension; + sourceDirectoryChanges.AddRange(from l in filteredSourceDirectoryFileTuples where l.Item2 > dateTime select l); + } + } + catch (Exception ex) + { + result += 1; + _Log.Error(string.Concat(group.SourceDirectory, Environment.NewLine, ex.Message, Environment.NewLine, ex.StackTrace), ex); + if (result == group.FilteredSourceDirectoryFiles.Length) + throw new Exception(string.Concat("All in [", group.SourceDirectory, "]failed!")); + } + }); + } + return result; + } + + private string SetAngleBracketCollectionAndGetZero(Configuration configuration, string sourceDirectory) + { + string result; + AngleBracketCollection.Clear(); + AngleBracketCollection.AddRange(IResult.GetDirectoryInfoCollection(configuration, + sourceDirectory, + nameof(A_Property), + string.Empty, + includeResizeGroup: false, + includeModel: false, + includePredictorModel: false, + contentDescription: string.Empty, + singletonDescription: "Properties for each image", + collectionDescription: string.Empty)); + result = AngleBracketCollection[0]; + return result; + } + + public List GetParallelWork(Configuration configuration, List topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> groupCollection, bool firstPass, bool filterOnFirstPass) + { + List results = new(); + if (_Log is null) + throw new Exception($"{nameof(_Log)} is null!"); + if (_Configuration.PopulatePropertyId is null) + throw new Exception($"{nameof(_Configuration.PopulatePropertyId)} is null!"); + Group group; + int exceptionCount; + string angleBracket; + object @lock = new(); + long ticks = DateTime.Now.Ticks; + string[] filteredSourceDirectoryFiles; + List> sourceDirectoryChanges = new(); + string propertyRoot = IResult.GetResultsGroupDirectory(configuration, nameof(A_Property)); + foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles, int r) in groupCollection) + { + if (!topDirectories.Any()) + continue; + sourceDirectoryChanges.Clear(); + if (firstPass && !filterOnFirstPass) + filteredSourceDirectoryFiles = sourceDirectoryFiles; + else + filteredSourceDirectoryFiles = (from l in sourceDirectoryFiles where !_Configuration.IgnoreExtensions.Contains(Path.GetExtension(l)) select l).ToArray(); + if (!filteredSourceDirectoryFiles.Any()) + continue; + group = new(g, sourceDirectory, filteredSourceDirectoryFiles, r); + angleBracket = SetAngleBracketCollectionAndGetZero(configuration, sourceDirectory); + exceptionCount = ParallelWork(firstPass, @lock, ticks, sourceDirectoryChanges, groupCollection.Count, group, angleBracket); + if (exceptionCount != 0) + _ExceptionsDirectories.Add(sourceDirectory); + else + results.Add(group); + bool? anyFilesMoved; + if (!firstPass || exceptionCount != 0) + anyFilesMoved = null; + else + anyFilesMoved = AnyFilesMoved(group); + if (exceptionCount != 0 || (anyFilesMoved is not null && anyFilesMoved.Value)) + results.Clear(); + if (exceptionCount == 0 && !firstPass && _Configuration.PopulatePropertyId.Value && (anyFilesMoved is null || !anyFilesMoved.Value)) + WriteGroup(group, angleBracket); + if (Directory.GetFiles(propertyRoot, "*.txt", SearchOption.TopDirectoryOnly).Any()) + { + for (int y = 0; y < int.MaxValue; y++) + { + _Log.Information("Press \"Y\" key when ready to continue or close console"); + if (Console.ReadKey().Key == ConsoleKey.Y) + break; + } + _Log.Information(". . ."); + } + } + return results; + } + + public List DoWork(Configuration configuration, List topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> groupCollection, bool firstPass) + { + List results = new(); + _ExceptionsDirectories.Clear(); + _ = GetParallelWork(configuration, topDirectories, groupCollection, firstPass, filterOnFirstPass: false); + results.AddRange(_ExceptionsDirectories); + return results; + } + + public A_Property GetProperty(string angleBracket, string sourceDirectory, string filteredSourceDirectoryFile, List> filteredSourceDirectoryFileTuples, List parseExceptions, FileInfo fileInfo) + { + A_Property result; + bool firstPass = false; + string extensionLowered = Path.GetExtension(filteredSourceDirectoryFile).ToLower(); + bool isValidMetadataExtensions = _Configuration.ValidMetadataExtensions.Contains(extensionLowered); + bool isValidImageFormatExtension = _Configuration.ValidImageFormatExtensions.Contains(extensionLowered); + bool isIgnoreExtension = isValidImageFormatExtension && _Configuration.IgnoreExtensions.Contains(extensionLowered); + string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(filteredSourceDirectoryFile); + string filteredSourceDirectoryFileExtensionLowered = Path.Combine(sourceDirectory, $"{fileNameWithoutExtension}{extensionLowered}"); + if (isValidImageFormatExtension && filteredSourceDirectoryFile.Length == filteredSourceDirectoryFileExtensionLowered.Length && filteredSourceDirectoryFile != filteredSourceDirectoryFileExtensionLowered) + File.Move(filteredSourceDirectoryFile, filteredSourceDirectoryFileExtensionLowered); + string without = Path.Combine(angleBracket.Replace("<>", "{}"), $"{fileNameWithoutExtension}.json"); + FileInfo propertyFileInfo = new(Path.Combine(angleBracket.Replace("<>", "{}"), $"{fileNameWithoutExtension}{extensionLowered}.json")); + if (isValidImageFormatExtension && File.Exists(without)) + { + File.Move(without, propertyFileInfo.FullName); + propertyFileInfo.Refresh(); + } + result = GetProperty(filteredSourceDirectoryFileTuples, parseExceptions, firstPass, angleBracket, filteredSourceDirectoryFile, fileInfo, isIgnoreExtension, isValidImageFormatExtension, isValidMetadataExtensions); + return result; + } + + public (long Ticks, string FilteredSourceDirectoryFile, string PropertyDirectory, int PropertyId)[] GetPropertyIds(Configuration configuration, List groupCollection, bool saveToCollection) + { + List<(long Ticks, string FilteredSourceDirectoryFile, string PropertyDirectory, int PropertyId)> results = new(); + int level; + string angleBracket; + A_Property? property; + string checkDirectory; + List directories; + string propertyDirectory; + foreach (Group group in groupCollection) + { + angleBracket = SetAngleBracketCollectionAndGetZero(configuration, group.SourceDirectory); + if (string.IsNullOrEmpty(group.SourceDirectory)) + throw new Exception(); + if (!saveToCollection) + propertyDirectory = angleBracket.Replace("<>", "()"); + else + { + (level, directories) = IPath.Get(_Configuration.RootDirectory, group.SourceDirectory); + checkDirectory = IPath.GetDirectory(angleBracket, level, "[()]"); + propertyDirectory = Path.Combine(checkDirectory, string.Join(_Configuration.FileNameDirectorySeparator, directories)); + } + if (!Directory.Exists(propertyDirectory)) + _ = Directory.CreateDirectory(propertyDirectory); + for (int i = 0; i < group.FilteredSourceDirectoryFiles.Length; i++) + { + property = group.PropertyCollection[i]; + if (property?.Id is null) + continue; + results.Add(new(property.GetDateTimes().Min().Ticks, group.FilteredSourceDirectoryFiles[i], propertyDirectory, property.Id.Value)); + } + } + return results.OrderBy(l => l.Ticks).ToArray(); + } + +} \ No newline at end of file diff --git a/Property/Models/Stateless/A_Property.cs b/Property/Models/Stateless/A_Property.cs new file mode 100644 index 0000000..bbc3879 --- /dev/null +++ b/Property/Models/Stateless/A_Property.cs @@ -0,0 +1,377 @@ +namespace View_by_Distance.Property.Models.Stateless; + +public static class A_Property +{ + + public static string DateTimeFormat() => "yyyy:MM:dd HH:mm:ss"; + + public static (int Season, string seasonName) GetSeason(int dayOfYear) + { + (int Season, string seasonName) result = dayOfYear switch + { + < 78 => new(0, "Winter"), + < 171 => new(1, "Spring"), + < 264 => new(2, "Summer"), + < 354 => new(3, "Fall"), + _ => new(4, "Winter") + }; + return result; + } + + public static List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> GetGroupCollection(string rootDirectory, string searchPattern, List topDirectories, int maxImagesInDirectoryForTopLevelFirstPass = 50, bool reverse = false) + { + List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> results = new(); + string? parentDirectory; + string[] subDirectories; + string[] sourceDirectoryFiles; + List fileCollections = new(); + if (!topDirectories.Any()) + { + topDirectories.Add(rootDirectory); + topDirectories.AddRange(from l in Directory.GetDirectories(rootDirectory, "*", SearchOption.TopDirectoryOnly) select Path.GetFullPath(l)); + } + for (int g = 1; g < 5; g++) + { + if (g == 4) + { + for (int i = fileCollections.Count - 1; i > -1; i--) + { + parentDirectory = Path.GetDirectoryName(fileCollections[i][0]); + if (string.IsNullOrEmpty(parentDirectory)) + continue; + results.Add(new(g, parentDirectory, fileCollections[i], results.Count)); + fileCollections.RemoveAt(i); + } + } + else if (g == 2) + { + fileCollections = (from l in fileCollections orderby l.Length descending select l).ToList(); + for (int i = fileCollections.Count - 1; i > -1; i--) + { + if (fileCollections[i].Length > maxImagesInDirectoryForTopLevelFirstPass * g) + break; + parentDirectory = Path.GetDirectoryName(fileCollections[i][0]); + if (string.IsNullOrEmpty(parentDirectory)) + continue; + results.Add(new(g, parentDirectory, fileCollections[i], results.Count)); + fileCollections.RemoveAt(i); + } + } + else if (g == 3) + { + subDirectories = Directory.GetDirectories(rootDirectory, "*", SearchOption.AllDirectories); + if (reverse) + subDirectories = subDirectories.Reverse().ToArray(); + foreach (string subDirectory in subDirectories) + { + sourceDirectoryFiles = Directory.GetFiles(subDirectory, "*", SearchOption.TopDirectoryOnly); + if (!topDirectories.Contains(subDirectory)) + results.Add(new(g, subDirectory, sourceDirectoryFiles, results.Count)); + } + } + else if (g == 1) + { + sourceDirectoryFiles = Directory.GetFiles(rootDirectory, searchPattern, SearchOption.TopDirectoryOnly); + if (sourceDirectoryFiles.Length > maxImagesInDirectoryForTopLevelFirstPass) + fileCollections.Add(sourceDirectoryFiles); + else + results.Add(new(g, rootDirectory, sourceDirectoryFiles, results.Count)); + if (reverse) + topDirectories.Reverse(); + subDirectories = topDirectories.ToArray(); + foreach (string subDirectory in subDirectories) + { + sourceDirectoryFiles = Directory.GetFiles(subDirectory, searchPattern, SearchOption.TopDirectoryOnly); + if (sourceDirectoryFiles.Length > maxImagesInDirectoryForTopLevelFirstPass) + fileCollections.Add(sourceDirectoryFiles); + else + { + if (sourceDirectoryFiles.Any() || Directory.GetDirectories(subDirectory, "*", SearchOption.TopDirectoryOnly).Any()) + results.Add(new(g, subDirectory, sourceDirectoryFiles, results.Count)); + else if (searchPattern == "*") + { + sourceDirectoryFiles = Directory.GetFiles(subDirectory, searchPattern, SearchOption.TopDirectoryOnly); + foreach (string subFile in sourceDirectoryFiles) + File.Delete(subFile); + Directory.Delete(subDirectory); + } + } + } + fileCollections.Reverse(); + } + else + throw new Exception(); + } + return results; + } + + public static int GetDeterministicHashCode(byte[] value) + { + int result; + unchecked + { + int hash1 = (5381 << 16) + 5381; + int hash2 = hash1; + for (int i = 0; i < value.Length; i += 2) + { + hash1 = ((hash1 << 5) + hash1) ^ value[i]; + if (i == value.Length - 1) + break; + hash2 = ((hash2 << 5) + hash2) ^ value[i + 1]; + } + result = hash1 + (hash2 * 1566083941); + } + return result; + } + + public static int GetDeterministicHashCode(string value) + { + int result; + unchecked + { + int hash1 = (5381 << 16) + 5381; + int hash2 = hash1; + for (int i = 0; i < value.Length; i += 2) + { + hash1 = ((hash1 << 5) + hash1) ^ value[i]; + if (i == value.Length - 1) + break; + hash2 = ((hash2 << 5) + hash2) ^ value[i + 1]; + } + result = hash1 + (hash2 * 1566083941); + } + return result; + } + + public static (bool?, string[]) IsWrongYear(string[] segments, string year) + { + bool? result; + string[] results = ( + from l + in segments + where l?.Length > 2 + && ( + l[..2] is "19" or "20" + || (l.Length == 5 && l.Substring(1, 2) is "19" or "20" && (l[0] is '~' or '=' or '-' or '^' or '#')) + || (l.Length == 6 && l[..2] is "19" or "20" && l[4] == '.') + || (l.Length == 7 && l.Substring(1, 2) is "19" or "20" && l[5] == '.') + ) + select l + ).ToArray(); + string[] matches = ( + from l + in results + where l == year + || (l.Length == 5 && l.Substring(1, 4) == year && (l[0] is '~' or '=' or '-' or '^' or '#')) + || (l.Length == 6 && l[..4] == year && l[4] == '.') + || (l.Length == 7 && l.Substring(1, 4) == year && l[5] == '.') + select l + ).ToArray(); + if (!results.Any()) + result = null; + else + result = !matches.Any(); + return new(result, results); + } + + public static List GetDateTimes(DateTime creationTime, DateTime lastWriteTime, DateTime? dateTime, DateTime? dateTimeDigitized, DateTime? dateTimeOriginal, DateTime? gpsDateStamp) + { + List results = new() + { + creationTime, + lastWriteTime + }; + if (dateTime.HasValue) + results.Add(dateTime.Value); + if (dateTimeDigitized.HasValue) + results.Add(dateTimeDigitized.Value); + if (dateTimeOriginal.HasValue) + results.Add(dateTimeOriginal.Value); + if (gpsDateStamp.HasValue) + results.Add(gpsDateStamp.Value); + return results; + } + + public static DateTime GetDateTime(Models.A_Property? property) + { + DateTime result; + if (property is null) + result = DateTime.MinValue; + else + { + List datetimes = new() + { + property.CreationTime, + property.LastWriteTime + }; + if (property.DateTime.HasValue) + datetimes.Add(property.DateTime.Value); + if (property.DateTimeDigitized.HasValue) + datetimes.Add(property.DateTimeDigitized.Value); + if (property.DateTimeOriginal.HasValue) + datetimes.Add(property.DateTimeOriginal.Value); + if (property.GPSDateStamp.HasValue) + datetimes.Add(property.GPSDateStamp.Value); + result = datetimes.Min(); + } + return result; + } + + public static List GetDateTimes(Models.A_Property property) => GetDateTimes(property.CreationTime, property.LastWriteTime, property.DateTime, property.DateTimeDigitized, property.DateTimeOriginal, property.GPSDateStamp); + + public static DateTime GetMinimumDateTime(Models.A_Property? property) + { + DateTime result; + List datetimes; + if (property is null) + result = DateTime.MinValue; + else + { + datetimes = GetDateTimes(property); + result = datetimes.Min(); + } + return result; + } + + public static string[] GetDirectoryRenameCollection(Models.Configuration configuration, string outputResolution, string bMetadata, string cResizeName) + { + List results = new(); + string cResizeContentDirectory; + string cResizeSingletonDirectory; + string bMetadataSingletonDirectory; + string aPropertySingletonDirectory; + bMetadataSingletonDirectory = IResult.GetResultsDateGroupDirectory(configuration, bMetadata, "{}"); + if (Directory.Exists(bMetadataSingletonDirectory)) + results.Add(bMetadataSingletonDirectory); + aPropertySingletonDirectory = IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "{}"); + if (Directory.Exists(aPropertySingletonDirectory)) + results.Add(aPropertySingletonDirectory); + cResizeContentDirectory = Path.Combine(IResult.GetResultsFullGroupDirectory(configuration, cResizeName, outputResolution, includeResizeGroup: true, includeModel: false, includePredictorModel: false), "()"); + if (Directory.Exists(cResizeContentDirectory)) + results.Add(cResizeContentDirectory); + cResizeSingletonDirectory = Path.Combine(IResult.GetResultsFullGroupDirectory(configuration, cResizeName, outputResolution, includeResizeGroup: true, includeModel: false, includePredictorModel: false), "{}"); + if (Directory.Exists(cResizeSingletonDirectory)) + results.Add(cResizeSingletonDirectory); + return results.ToArray(); + } + + public static void SearchForAbandonedFilesFull(string argZero, string rootDirectory, bool onlyJson) + { + bool check; + string[] files; + string moveFile; + string extension; + string? directory; + const int last = 6; + string searchPattern; + string searchDirectory; + int lessThan = last + 1; + string? parentDirectory; + DirectoryInfo directoryInfo; + string fileNameWithoutExtension; + IEnumerator enumerator; + List fileMovePaths = new(); + List toReviewFiles = new(); + int rootDirectoryLength = rootDirectory.Length; + for (int i = 1; i < lessThan; i++) + { + files = i switch + { + 1 => Directory.GetFiles(rootDirectory, "*.json", SearchOption.AllDirectories), + 2 => Directory.GetFiles(rootDirectory, "*.nosj", SearchOption.AllDirectories), + 3 => Directory.GetFiles(rootDirectory, "*.jpeg", SearchOption.AllDirectories), + 4 => Directory.GetFiles(rootDirectory, "*.tvs", SearchOption.AllDirectories), + 5 => Directory.GetFiles(rootDirectory, "*.png", SearchOption.AllDirectories), + last => Directory.GetFiles(rootDirectory, "*", SearchOption.AllDirectories), + _ => Array.Empty() + }; + foreach (string file in files) + { + extension = Path.GetExtension(file); + if (extension == ".delete") + continue; + directory = Path.GetDirectoryName(file); + if (string.IsNullOrEmpty(directory)) + continue; + fileNameWithoutExtension = Path.GetFileNameWithoutExtension(file); + if (file.EndsWith(" - R.png")) + continue; + if (fileNameWithoutExtension.Length < 1) + continue; + if (fileNameWithoutExtension[1..] != string.Concat(" - ", Path.GetFileNameWithoutExtension(directory))) + { + searchPattern = string.Concat(fileNameWithoutExtension, '*'); + searchDirectory = string.Concat(argZero, directory[rootDirectoryLength..]); + } + else + { + if (fileNameWithoutExtension.Length < 4) + continue; + searchPattern = string.Concat(fileNameWithoutExtension[4..], '*'); + parentDirectory = Path.GetDirectoryName(directory); + if (string.IsNullOrEmpty(parentDirectory)) + continue; + searchDirectory = string.Concat(argZero, parentDirectory[rootDirectoryLength..]); + } + directoryInfo = new(searchDirectory); + if (!directoryInfo.Exists) + check = false; + else + { + enumerator = directoryInfo.EnumerateFiles(searchPattern, SearchOption.TopDirectoryOnly).GetEnumerator(); + check = enumerator.MoveNext(); + } + if (check) + continue; + toReviewFiles.Add(file); + } + if (toReviewFiles.Any()) + throw new Exception("Need to fix property having the extension before .json extension!"); + foreach (string toReviewFile in toReviewFiles) + { + extension = Path.GetExtension(toReviewFile); + if (extension == ".delete") + continue; + directory = Path.GetDirectoryName(toReviewFile); + if (string.IsNullOrEmpty(directory)) + continue; + moveFile = Path.Combine(directory, Path.ChangeExtension(toReviewFile, ".delete")); + if (i == last) + fileMovePaths.Add(new string[] { toReviewFile, moveFile }); + else if (extension is ".nosj") + File.Delete(toReviewFile); + else + { + if (File.Exists(moveFile)) + File.Delete(moveFile); + File.Move(toReviewFile, moveFile); + } + } + toReviewFiles.Clear(); + if (onlyJson) + break; + } + if (fileMovePaths.Any()) + throw new Exception(string.Join(',', (from l in fileMovePaths select l[0]).ToArray())); + } + + public static string GetDiffRootDirectory(string diffPropertyDirectory) + { + string result = string.Empty; + string results = " - Results"; + string? checkDirectory = diffPropertyDirectory; + for (int i = 0; i < int.MaxValue; i++) + { + checkDirectory = Path.GetDirectoryName(checkDirectory); + if (string.IsNullOrEmpty(checkDirectory)) + break; + if (checkDirectory.EndsWith(results)) + { + result = checkDirectory[..^results.Length]; + break; + } + } + return result; + } + +} \ No newline at end of file diff --git a/Property/Models/Stateless/Configuration.cs b/Property/Models/Stateless/Configuration.cs new file mode 100644 index 0000000..25574b2 --- /dev/null +++ b/Property/Models/Stateless/Configuration.cs @@ -0,0 +1,42 @@ +using Microsoft.Extensions.Configuration; +using Phares.Shared; +using System.Text.Json; + +namespace View_by_Distance.Property.Models.Stateless; + +public abstract class Configuration +{ + + public static Models.Configuration Get(IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, string workingDirectory) + { + Models.Configuration? result; + string environmentName = IsEnvironment.GetEnvironmentName(isEnvironment); + string section = string.Concat(environmentName, ":", nameof(Binder.Configuration)); + IConfigurationSection configurationSection = configurationRoot.GetSection(section); + Binder.Configuration configuration = configurationSection.Get(); + string json = JsonSerializer.Serialize(configuration, new JsonSerializerOptions() { WriteIndented = true }); + result = JsonSerializer.Deserialize(json); + if (result is null) + throw new Exception(json); + string jsonThis = result.ToString(); + if (jsonThis != json) + { + int? check = null; + int min = new int[] { json.Length, jsonThis.Length }.Min(); + for (int i = 0; i < min; i++) + { + if (json[i] == jsonThis[i]) + continue; + check = i; + break; + } + if (check is null) + throw new Exception(); + string a = json[..check.Value].Split(',')[^1]; + string b = json[check.Value..].Split(',')[0]; + throw new Exception($"{a}{b}"); + } + return result; + } + +} \ No newline at end of file diff --git a/Property/Models/Stateless/IPath.cs b/Property/Models/Stateless/IPath.cs new file mode 100644 index 0000000..591d8cb --- /dev/null +++ b/Property/Models/Stateless/IPath.cs @@ -0,0 +1,24 @@ +namespace View_by_Distance.Property.Models.Stateless; + +public interface IPath +{ + + string TestStatic_GetRelativePath(string path, int length); + static string GetRelativePath(string path, int length) => XPath.GetRelativePath(path, length); + + bool TestStatic_DeleteEmptyDirectories(string rootDirectory); + static bool DeleteEmptyDirectories(string rootDirectory) => XPath.DeleteEmptyDirectories(rootDirectory); + + List TestStatic_GetDirectoryNames(string directory); + static List GetDirectoryNames(string directory) => XPath.GetDirectoryNames(directory); + + bool TestStatic_WriteAllText(string path, string contents, bool compareBeforeWrite); + static bool WriteAllText(string path, string contents, bool compareBeforeWrite) => XPath.WriteAllText(path, contents, compareBeforeWrite); + + (int level, List directories) TestStatic_Get(string rootDirectory, string sourceDirectory); + static (int level, List directories) Get(string rootDirectory, string sourceDirectory) => XPath.Get(rootDirectory, sourceDirectory); + + string TestStatic_GetDirectory(string sourceDirectory, int level, string directoryName); + static string GetDirectory(string sourceDirectory, int level, string directoryName) => XPath.GetDirectory(sourceDirectory, level, directoryName); + +} \ No newline at end of file diff --git a/Property/Models/Stateless/IResult.cs b/Property/Models/Stateless/IResult.cs new file mode 100644 index 0000000..0bde5ed --- /dev/null +++ b/Property/Models/Stateless/IResult.cs @@ -0,0 +1,24 @@ +namespace View_by_Distance.Property.Models.Stateless; + +public interface IResult +{ + + string TestStatic_GetRelativePath(Models.Configuration configuration, string path); + static string GetRelativePath(Models.Configuration configuration, string path) => Result.GetRelativePath(configuration, path); + + string TestStatic_GetResultsGroupDirectory(Models.Configuration configuration, string description); + static string GetResultsGroupDirectory(Models.Configuration configuration, string description) => Result.GetResultsGroupDirectory(configuration, description); + + string TestStatic_GetResultsDateGroupDirectory(Models.Configuration configuration, string description); + static string GetResultsDateGroupDirectory(Models.Configuration configuration, string description) => Result.GetResultsDateGroupDirectory(configuration, description); + + string TestStatic_GetResultsDateGroupDirectory(Models.Configuration configuration, string description, string jsonGroup); + static string GetResultsDateGroupDirectory(Models.Configuration configuration, string description, string jsonGroup) => Result.GetResultsDateGroupDirectory(configuration, description, jsonGroup); + + string TestStatic_GetResultsFullGroupDirectory(Models.Configuration configuration, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel); + static string GetResultsFullGroupDirectory(Models.Configuration configuration, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel) => Result.GetResultsFullGroupDirectory(configuration, description, outputResolution, includeResizeGroup, includeModel, includePredictorModel); + + List TestStatic_GetDirectoryInfoCollection(Models.Configuration configuration, string sourceDirectory, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel, string contentDescription, string singletonDescription, string collectionDescription); + static List GetDirectoryInfoCollection(Models.Configuration configuration, string sourceDirectory, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel, string contentDescription, string singletonDescription, string collectionDescription) => Result.GetDirectoryInfoCollection(configuration, sourceDirectory, description, outputResolution, includeResizeGroup, includeModel, includePredictorModel, contentDescription, singletonDescription, collectionDescription); + +} \ No newline at end of file diff --git a/Property/Models/Stateless/Path.cs b/Property/Models/Stateless/Path.cs new file mode 100644 index 0000000..184668c --- /dev/null +++ b/Property/Models/Stateless/Path.cs @@ -0,0 +1,143 @@ +namespace View_by_Distance.Property.Models.Stateless; + +internal class XPath +{ + + internal static string GetRelativePath(string path, int length) + { + string result = path[length..].Replace(@"\", "/"); + return result; + } + + internal static bool DeleteEmptyDirectories(string rootDirectory) + { + bool result; + if (!Directory.Exists(rootDirectory)) + result = false; + else + { + string[] files; + string[] directories = Directory.GetDirectories(rootDirectory, "*", SearchOption.TopDirectoryOnly); + if (directories.Length > 0) + files = Array.Empty(); + else + files = Directory.GetFiles(rootDirectory, "*", SearchOption.AllDirectories); + if (directories.Length == 0 && files.Length == 0) + { + result = true; + Directory.Delete(rootDirectory); + } + else + { + result = false; + foreach (string directory in directories) + { + result = DeleteEmptyDirectories(directory); + if (result) + result = DeleteEmptyDirectories(directory); + } + if (files is null) + { + directories = Directory.GetDirectories(rootDirectory, "*", SearchOption.TopDirectoryOnly); + result = directories.Length == 0; + } + } + } + return result; + } + + internal static bool WriteAllText(string path, string contents, bool compareBeforeWrite) + { + bool result; + string text; + if (!compareBeforeWrite) + result = true; + else + { + if (!File.Exists(path)) + text = string.Empty; + else + text = File.ReadAllText(path); + result = text != contents; + } + if (result) + { + if (path.Contains("()")) + File.WriteAllText(path, contents); + else if (path.Contains("{}") && !path.EndsWith(".json")) + File.WriteAllText(path, contents); + else if (path.Contains("[]") && !path.EndsWith(".json")) + File.WriteAllText(path, contents); + else if (path.Contains("{}") && path.EndsWith(".json") && contents[0] == '{') + File.WriteAllText(path, contents); + else if (path.Contains("[]") && path.EndsWith(".json") && contents[0] == '[') + File.WriteAllText(path, contents); + else + File.WriteAllText(path, contents); + } + return result; + } + + internal static List GetDirectoryNames(string directory) + { + List results = new(); + string? checkDirectory = directory; + string? pathRoot = Path.GetPathRoot(directory); + string extension = Path.GetExtension(directory); + if (string.IsNullOrEmpty(pathRoot)) + throw new Exception($"{nameof(pathRoot)} is null!"); + if (Directory.Exists(directory)) + results.Add(Path.GetFileName(directory)); + else if ((string.IsNullOrEmpty(extension) || extension.Length > 3) && !File.Exists(directory)) + results.Add(Path.GetFileName(directory)); + for (int i = 0; i < int.MaxValue; i++) + { + checkDirectory = Path.GetDirectoryName(checkDirectory); + if (string.IsNullOrEmpty(checkDirectory) || checkDirectory == pathRoot) + break; + results.Add(Path.GetFileName(checkDirectory)); + } + results.Add(pathRoot); + results.Reverse(); + return results; + } + + internal static (int level, List directories) Get(string rootDirectory, string sourceDirectory) + { + int result = 0; + string? directory; + string? checkDirectory; + List results = new(); + checkDirectory = sourceDirectory; + for (int i = 0; i < int.MaxValue; i++) + { + result += 1; + directory = Path.GetFileName(checkDirectory); + if (string.IsNullOrEmpty(directory)) + break; + results.Add(directory); + checkDirectory = Path.GetDirectoryName(checkDirectory); + if (checkDirectory == rootDirectory) + break; + } + results.Reverse(); + return new(result, results); + } + + internal static string GetDirectory(string sourceDirectory, int level, string directoryName) + { + string result; + string? checkDirectory; + checkDirectory = Path.GetDirectoryName(sourceDirectory); + for (int i = 0; i < level; i++) + checkDirectory = Path.GetDirectoryName(checkDirectory); + if (string.IsNullOrEmpty(checkDirectory)) + throw new Exception(); + checkDirectory = Path.Combine(checkDirectory, directoryName); + if (!Directory.Exists(checkDirectory)) + _ = Directory.CreateDirectory(checkDirectory); + result = checkDirectory; + return result; + } + +} \ No newline at end of file diff --git a/Property/Models/Stateless/Result.cs b/Property/Models/Stateless/Result.cs new file mode 100644 index 0000000..531f4dc --- /dev/null +++ b/Property/Models/Stateless/Result.cs @@ -0,0 +1,98 @@ +namespace View_by_Distance.Property.Models.Stateless; + +internal class Result +{ + + internal static string GetRelativePath(Models.Configuration configuration, string path) + { + string result = XPath.GetRelativePath(path, configuration.RootDirectory.Length); + return result; + } + + internal static string GetResultsGroupDirectory(Models.Configuration configuration, string description) + { + string result = Path.Combine($"{configuration.RootDirectory} - Results", description.Replace("_", ") ")); + if (!Directory.Exists(result)) + _ = Directory.CreateDirectory(result); + return result; + } + + internal static string GetResultsDateGroupDirectory(Models.Configuration configuration, string description) + { + string result = Path.Combine(GetResultsGroupDirectory(configuration, description), configuration.DateGroup); + if (!Directory.Exists(result)) + _ = Directory.CreateDirectory(result); + return result; + } + + internal static string GetResultsDateGroupDirectory(Models.Configuration configuration, string description, string jsonGroup) + { + string result = Path.Combine(GetResultsDateGroupDirectory(configuration, description), jsonGroup); + if (!Directory.Exists(result)) + _ = Directory.CreateDirectory(result); + return result; + } + + internal static string GetResultsFullGroupDirectory(Models.Configuration configuration, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel) + { + string result = GetResultsDateGroupDirectory(configuration, description); + if (includeResizeGroup) + result = Path.Combine(result, outputResolution); + if (includeModel && includePredictorModel) + { + string dateGroupDirectory = string.Concat(outputResolution.Replace(" ", string.Empty), " - ", "_Configuration.ModelName", " - ", "_Configuration.PredictorModelName"); + result = Path.Combine(result, dateGroupDirectory); + } + else if (includeModel) + throw new Exception(); + else if (includePredictorModel) + throw new Exception(); + if (!Directory.Exists(result)) + _ = Directory.CreateDirectory(result); + return result; + } + + internal static List GetDirectoryInfoCollection(Models.Configuration configuration, string sourceDirectory, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel, string contentDescription, string singletonDescription, string collectionDescription) + { + List results = new(); + string result = string.Empty; + string checkDirectory; + string sourceDirectorySegment = GetRelativePath(configuration, sourceDirectory); + string dateGroupDirectory = IResult.GetResultsFullGroupDirectory(configuration, description, outputResolution, includeResizeGroup, includeModel, includePredictorModel); + if (!string.IsNullOrEmpty(contentDescription)) + { + result = string.Concat(Path.Combine(dateGroupDirectory, "<>"), sourceDirectorySegment); + DirectoryInfo contentDirectoryInfo = new(result.Replace("<>", "()")); + if (!contentDirectoryInfo.Exists) + contentDirectoryInfo.Create(); + checkDirectory = Path.Combine(dateGroupDirectory, string.Concat("() - ", contentDescription)); + if (!Directory.Exists(checkDirectory)) + _ = Directory.CreateDirectory(checkDirectory); + } + if (!string.IsNullOrEmpty(singletonDescription)) + { + result = string.Concat(Path.Combine(dateGroupDirectory, "<>"), sourceDirectorySegment); + DirectoryInfo singletonDirectoryInfo = new(result.Replace("<>", "{}")); + if (!singletonDirectoryInfo.Exists) + singletonDirectoryInfo.Create(); + checkDirectory = Path.Combine(dateGroupDirectory, string.Concat("{} - ", singletonDescription)); + if (!Directory.Exists(checkDirectory)) + _ = Directory.CreateDirectory(checkDirectory); + } + if (!string.IsNullOrEmpty(collectionDescription)) + { + result = string.Concat(Path.Combine(dateGroupDirectory, "<>"), sourceDirectorySegment); + DirectoryInfo collectionDirectoryInfo = new(result.Replace("<>", "[]")); + if (!collectionDirectoryInfo.Exists) + collectionDirectoryInfo.Create(); + checkDirectory = Path.Combine(dateGroupDirectory, string.Concat("[] - ", collectionDescription)); + if (!Directory.Exists(checkDirectory)) + _ = Directory.CreateDirectory(checkDirectory); + } + if (string.IsNullOrEmpty(result)) + throw new Exception(); + results.Add(result); + return results; + } + +} \ No newline at end of file diff --git a/Property/Models/Stateless/SerilogExtensionMethods.cs b/Property/Models/Stateless/SerilogExtensionMethods.cs new file mode 100644 index 0000000..1b1fd86 --- /dev/null +++ b/Property/Models/Stateless/SerilogExtensionMethods.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Property.Models.Stateless; + +internal static class SerilogExtensionMethods +{ + + internal static void Warn(this Serilog.ILogger log, string messageTemplate) => log.Warning(messageTemplate); + + internal static void Info(this Serilog.ILogger log, string messageTemplate) => log.Information(messageTemplate); + +} \ No newline at end of file diff --git a/Property/Property.csproj b/Property/Property.csproj new file mode 100644 index 0000000..36837c5 --- /dev/null +++ b/Property/Property.csproj @@ -0,0 +1,58 @@ + + + enable + 10.0 + enable + library + win-x64 + net6.0 + + + Phares.View.by.Distance.Property + false + 5.0.402.104 + Mike Phares + Phares + true + snupkg + + + + true + + + true + + + true + + + + Windows + + + OSX + + + Linux + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Resize/.vscode/format-report.json b/Resize/.vscode/format-report.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/Resize/.vscode/format-report.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/Resize/.vscode/settings.json b/Resize/.vscode/settings.json new file mode 100644 index 0000000..0852522 --- /dev/null +++ b/Resize/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "cSpell.words": [ + "dlib", + "Exif", + "nosj", + "Serilog" + ] +} \ No newline at end of file diff --git a/Resize/Models/Stateless/SerilogExtensionMethods.cs b/Resize/Models/Stateless/SerilogExtensionMethods.cs new file mode 100644 index 0000000..1e775eb --- /dev/null +++ b/Resize/Models/Stateless/SerilogExtensionMethods.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Resize.Models.Stateless; + +internal static class SerilogExtensionMethods +{ + + internal static void Warn(this Serilog.ILogger log, string messageTemplate) => log.Warning(messageTemplate); + + internal static void Info(this Serilog.ILogger log, string messageTemplate) => log.Information(messageTemplate); + +} \ No newline at end of file diff --git a/Resize/Models/_C_Resize.cs b/Resize/Models/_C_Resize.cs new file mode 100644 index 0000000..2861cca --- /dev/null +++ b/Resize/Models/_C_Resize.cs @@ -0,0 +1,534 @@ +using System.Drawing; +using System.Drawing.Imaging; +using System.Globalization; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Text.Json; +using View_by_Distance.Metadata.Models; +using View_by_Distance.Property.Models; +using View_by_Distance.Shared.Models.Stateless; + +namespace View_by_Distance.Resize.Models; + +/// +// Dictionary +/// +public class C_Resize +{ + + public List AngleBracketCollection { get; } + + private readonly Serilog.ILogger? _Log; + private readonly string[] _ValidResolutions; + private readonly ASCIIEncoding _ASCIIEncoding; + private readonly bool _OverrideForResizeImages; + private readonly ImageCodecInfo _ImageCodecInfo; + private readonly ConstructorInfo _ConstructorInfo; + private readonly bool _PropertiesChangedForResize; + private readonly EncoderParameters _EncoderParameters; + private readonly bool _ForceResizeLastWriteTimeToCreationTime; + private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions; + + public C_Resize(bool forceResizeLastWriteTimeToCreationTime, bool overrideForResizeImages, bool propertiesChangedForResize, string[] validResolutions, ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters) + { + _ImageCodecInfo = imageCodecInfo; + _ASCIIEncoding = new ASCIIEncoding(); + _ValidResolutions = validResolutions; + _EncoderParameters = encoderParameters; + _Log = Serilog.Log.ForContext(); + AngleBracketCollection = new List(); + _OverrideForResizeImages = overrideForResizeImages; + _PropertiesChangedForResize = propertiesChangedForResize; + _ForceResizeLastWriteTimeToCreationTime = forceResizeLastWriteTimeToCreationTime; + _WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true }; + ConstructorInfo? constructorInfo = typeof(PropertyItem).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, Array.Empty(), null); + if (constructorInfo is null) + throw new Exception(); + _ConstructorInfo = constructorInfo; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +#pragma warning disable CA1416 + + public static (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters) GetTuple(string outputExtension, int outputQuality) + { + (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters) result; + ImageFormat imageFormat = outputExtension switch + { + ".gif" => ImageFormat.Gif, + ".jpg" => ImageFormat.Jpeg, + ".png" => ImageFormat.Png, + ".tiff" => ImageFormat.Tiff, + _ => throw new Exception(), + }; + ImageCodecInfo imageCodecInfo = (from l in ImageCodecInfo.GetImageEncoders() where l.FormatID == imageFormat.Guid select l).First(); + EncoderParameters encoderParameters = new(1); + // encoderParameters.Param[0] = New EncoderParameter(System.Drawing.Imaging.Encoder.Quality, CType(75L, Int32)) 'Default + // encoderParameters.Param[0] = New EncoderParameter(System.Drawing.Imaging.Encoder.Quality, CType(95L, Int32)) 'Paint + encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, outputQuality); + result = new(imageCodecInfo, encoderParameters); + return result; + } + + public static byte[] GetBitmapData(Bitmap bitmap) + { + byte[] results; + Rectangle rectangle = new(0, 0, bitmap.Width, bitmap.Height); + BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, bitmap.PixelFormat); + IntPtr intPtr = bitmapData.Scan0; + int length = bitmapData.Stride * bitmap.Height; + results = new byte[length]; + Marshal.Copy(intPtr, results, 0, length); + bitmap.UnlockBits(bitmapData); + return results; + } + + private void CopyPropertyItems(byte[] bytes, PropertyItem[] propertyItems, Bitmap bitmap) + { + bool hasId = false; + int id = (int)IExif.Tags.DateTimeDigitized; + foreach (PropertyItem propertyItem in propertyItems) + { + if (propertyItem.Id == id) + hasId = true; + bitmap.SetPropertyItem(propertyItem); + } + if (!hasId) + { + PropertyItem propertyItem = (PropertyItem)_ConstructorInfo.Invoke(null); + propertyItem.Id = id; + propertyItem.Len = bytes.Length; + propertyItem.Type = 2; + propertyItem.Value = bytes; + bitmap.SetPropertyItem(propertyItem); + } + } + + private byte[] SaveResizedSubfile3(string subFile, int[] resize, byte[] bytes, FileInfo? fileInfo) + { + byte[] results; + Bitmap bitmap; + int outputResolutionWidth = resize[0]; + int outputResolutionHeight = resize[1]; + int outputResolutionOrientation = resize[2]; + using Bitmap temp = new(subFile, useIcm: false); + PropertyItem[] propertyItems = temp.PropertyItems; + switch (outputResolutionOrientation) // exif 274 + { + case 0: + bitmap = new(temp, outputResolutionWidth, outputResolutionHeight); + break; + case 1: + bitmap = new(temp, outputResolutionWidth, outputResolutionHeight); + break; // 1 = Horizontal (normal) + case 2: + bitmap = new(temp, outputResolutionWidth, outputResolutionHeight); + bitmap.RotateFlip(RotateFlipType.RotateNoneFlipX); + break; // 2 = Mirror horizontal + case 3: + bitmap = new(temp, outputResolutionWidth, outputResolutionHeight); + bitmap.RotateFlip(RotateFlipType.Rotate180FlipNone); + break; // 3 = Rotate 180 + case 4: + bitmap = new(temp, outputResolutionWidth, outputResolutionHeight); + bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY); + break; // 4 = Mirror vertical + case 5: + bitmap = new(temp, outputResolutionHeight, outputResolutionWidth); + bitmap.RotateFlip(RotateFlipType.Rotate270FlipX); + break; // 5 = Mirror horizontal and rotate 270 CW + case 6: + bitmap = new(temp, outputResolutionHeight, outputResolutionWidth); + bitmap.RotateFlip(RotateFlipType.Rotate90FlipNone); + break; // 6 = Rotate 90 CW + case 7: + bitmap = new(temp, outputResolutionHeight, outputResolutionWidth); + bitmap.RotateFlip(RotateFlipType.Rotate90FlipX); + break; // 7 = Mirror horizontal and rotate 90 CW + case 8: + bitmap = new(temp, outputResolutionHeight, outputResolutionWidth); + bitmap.RotateFlip(RotateFlipType.Rotate270FlipNone); + break; // 8 = Rotate 270 CW + default: + bitmap = new(temp, outputResolutionWidth, outputResolutionHeight); + break; + } + if (fileInfo is null) + results = GetBitmapData(bitmap); + else + { + results = Array.Empty(); + CopyPropertyItems(bytes, propertyItems, bitmap); + bitmap.Save(fileInfo.FullName, _ImageCodecInfo, _EncoderParameters); + } + bitmap.Dispose(); + return results; + } + + private byte[] SaveResizedSubfile5(string subFile, int[] resize, byte[] bytes, FileInfo? fileInfo) + { + byte[] results; + Bitmap bitmap; + int tempResolutionWidth = resize[3]; + int tempResolutionHeight = resize[4]; + int outputResolutionWidth = resize[0]; + int outputResolutionHeight = resize[1]; + int outputResolutionOrientation = resize[2]; + using Bitmap temp = new(subFile, useIcm: false); + PropertyItem[] propertyItems = temp.PropertyItems; + switch (outputResolutionOrientation) // exif 274 + { + case 0: + bitmap = new(temp, tempResolutionWidth, tempResolutionHeight); + break; + case 1: + bitmap = new(temp, tempResolutionWidth, tempResolutionHeight); + break; // 1 = Horizontal (normal) + case 2: + bitmap = new(temp, tempResolutionWidth, tempResolutionHeight); + bitmap.RotateFlip(RotateFlipType.RotateNoneFlipX); + break; // 2 = Mirror horizontal + case 3: + bitmap = new(temp, tempResolutionWidth, tempResolutionHeight); + bitmap.RotateFlip(RotateFlipType.Rotate180FlipNone); + break; // 3 = Rotate 180 + case 4: + bitmap = new(temp, tempResolutionWidth, tempResolutionHeight); + bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY); + break; // 4 = Mirror vertical + case 5: + bitmap = new(temp, tempResolutionHeight, tempResolutionWidth); + bitmap.RotateFlip(RotateFlipType.Rotate270FlipX); + break; // 5 = Mirror horizontal and rotate 270 CW + case 6: + bitmap = new(temp, tempResolutionHeight, tempResolutionWidth); + bitmap.RotateFlip(RotateFlipType.Rotate90FlipNone); + break; // 6 = Rotate 90 CW + case 7: + bitmap = new(temp, tempResolutionHeight, tempResolutionWidth); + bitmap.RotateFlip(RotateFlipType.Rotate90FlipX); + break; // 7 = Mirror horizontal and rotate 90 CW + case 8: + bitmap = new(temp, tempResolutionHeight, tempResolutionWidth); + bitmap.RotateFlip(RotateFlipType.Rotate270FlipNone); + break; // 8 = Rotate 270 CW + default: + bitmap = new(temp, tempResolutionWidth, tempResolutionHeight); + break; + } + Bitmap preRotated; + Rectangle rectangle; + if (tempResolutionHeight < tempResolutionWidth) + rectangle = new Rectangle((int)((tempResolutionWidth - outputResolutionWidth) * .5), 0, outputResolutionWidth, outputResolutionHeight); + else + rectangle = new Rectangle(0, (int)((tempResolutionHeight - outputResolutionHeight) * .5), outputResolutionWidth, outputResolutionHeight); + using (preRotated = new Bitmap(outputResolutionWidth, outputResolutionHeight)) + { + using (Graphics graphics = Graphics.FromImage(preRotated)) + graphics.DrawImage(bitmap, new Rectangle(0, 0, outputResolutionWidth, outputResolutionHeight), rectangle, GraphicsUnit.Pixel); + if (fileInfo is null) + results = GetBitmapData(bitmap); + else + { + results = Array.Empty(); + CopyPropertyItems(bytes, propertyItems, bitmap); + bitmap.Save(fileInfo.FullName, _ImageCodecInfo, _EncoderParameters); + } + } + bitmap.Dispose(); + return results; + } + +#pragma warning restore CA1416 + + private byte[] SaveResizedSubfile(string subFile, A_Property property, int[] resize, FileInfo? fileInfo) + { + byte[] results; + string dateTimeFormat = Property.Models.Stateless.A_Property.DateTimeFormat(); + DateTime dateTime = Property.Models.Stateless.A_Property.GetMinimumDateTime(property); + string dateTimeValue = dateTime.ToString(dateTimeFormat); + byte[] bytes = _ASCIIEncoding.GetBytes(dateTimeValue); + if (_ASCIIEncoding.GetString(bytes, 0, bytes.Length) != dateTimeValue) + throw new Exception(); + if (resize.Length == 3) + results = SaveResizedSubfile3(subFile, resize, bytes, fileInfo); + else if (resize.Length == 5) + results = SaveResizedSubfile5(subFile, resize, bytes, fileInfo); + else + throw new Exception(); + if (fileInfo is not null && false) + { +#pragma warning disable CA1416 + using Image image = Image.FromFile(fileInfo.FullName); + if (image.PropertyIdList.Contains((int)IExif.Tags.DateTimeDigitized)) + { + string value; + DateTime checkDateTime; + PropertyItem? propertyItem = image.GetPropertyItem((int)IExif.Tags.DateTimeDigitized); + if (propertyItem?.Value is not null) + { + value = _ASCIIEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); + if (value.Length == dateTimeFormat.Length && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out checkDateTime)) + _ = checkDateTime; + } + } +#pragma warning restore CA1416 + } + return results; + } + + public byte[] GetResizedBytes(string outputResolution, List> subFileTuples, string subFile, A_Property property, Dictionary imageResizes) + { + byte[] results; + if (!imageResizes.ContainsKey(outputResolution)) + throw new Exception(); + int[] resize = imageResizes[outputResolution]; + int outputResolutionWidth = resize[0]; + int outputResolutionHeight = resize[1]; + int outputResolutionOrientation = resize[2]; + results = SaveResizedSubfile(subFile, property, resize, fileInfo: null); + subFileTuples.Add(new Tuple(nameof(C_Resize), DateTime.Now)); + return results; + } + + public void SaveResizedSubfile(string outputResolution, List> subFileTuples, string subFile, string original, A_Property property, Dictionary imageResizes, FileInfo fileInfo) + { + if (!imageResizes.ContainsKey(outputResolution)) + throw new Exception(); + if (!fileInfo.Exists) + { + if (fileInfo.Directory?.Parent is null) + throw new Exception(); + string parentCheck = Path.Combine(fileInfo.Directory.Parent.FullName, fileInfo.Name); + if (File.Exists(parentCheck)) + { + File.Move(parentCheck, fileInfo.FullName); + fileInfo.Refresh(); + } + } + int[] resize = imageResizes[outputResolution]; + int outputResolutionWidth = resize[0]; + int outputResolutionHeight = resize[1]; + int outputResolutionOrientation = resize[2]; + int[] originalCollection = imageResizes[original]; + if (outputResolutionWidth == originalCollection[0] && outputResolutionHeight == originalCollection[1] && outputResolutionOrientation == originalCollection[2]) + { + if (!fileInfo.Exists) + { + File.Copy(subFile, fileInfo.FullName); + subFileTuples.Add(new Tuple(nameof(C_Resize), DateTime.Now)); + } + } + else + { + bool check = false; + string[] changesFrom = new string[] { nameof(A_Property), nameof(B_Metadata), nameof(C_Resize) }; + List dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); + if (_OverrideForResizeImages) + check = true; + else if (!fileInfo.Exists) + check = true; + else if (dateTimes.Any() && dateTimes.Max() > fileInfo.LastWriteTime) + check = true; + if (check) + { + _ = SaveResizedSubfile(subFile, property, resize, fileInfo); + subFileTuples.Add(new Tuple(nameof(C_Resize), DateTime.Now)); + } + } + } + + private int[] GetCollection(string outputResolution) + { + if (_Log is null) + { } + List results = new(); + string[] segments = outputResolution.Split('x'); + results.Add(int.Parse(segments[0])); + results.Add(int.Parse(segments[1])); + return results.ToArray(); + } + + private static int GetOrientation(List> metadataCollection) + { + int result; + const string orientation = nameof(IExif.Tags.Orientation); + List orientations = (from l in metadataCollection where l.Key.Contains(orientation) select l.Value).ToList(); + if (!orientations.Any()) + result = 0; + else if (!int.TryParse(orientations[0], out result)) + result = 0; + return result; + } + + private Dictionary GetImageResizes(List> metadataCollection, A_Property property, string original) + { + Dictionary results = new(); + int[] desired; + int checkWidth; + int orientation; + int checkHeight; + int desiredWidth; + int desiredHeight; + if (property is null || property.Width is null || property.Height is null) + throw new Exception(); + if (!string.IsNullOrEmpty(property.Orientation) && int.TryParse(property.Orientation, out int propertyOrientation)) + orientation = propertyOrientation; + else + orientation = GetOrientation(metadataCollection); + switch (orientation) // exif 274 + { + case 0: + checkWidth = property.Width.Value; + checkHeight = property.Height.Value; + break; + case 1: + checkWidth = property.Width.Value; + checkHeight = property.Height.Value; + break; // 1 = Horizontal (normal) + case 2: + checkWidth = property.Width.Value; + checkHeight = property.Height.Value; + break; // 2 = Mirror horizontal + case 3: + checkWidth = property.Width.Value; + checkHeight = property.Height.Value; + break; // 3 = Rotate 180 + case 4: + checkWidth = property.Width.Value; + checkHeight = property.Height.Value; + break; // 4 = Mirror vertical + case 5: + checkWidth = property.Height.Value; + checkHeight = property.Width.Value; + break; // 5 = Mirror horizontal and rotate 270 CW + case 6: + checkWidth = property.Height.Value; + checkHeight = property.Width.Value; + break; // 6 = Rotate 90 CW + case 7: + checkWidth = property.Height.Value; + checkHeight = property.Width.Value; + break; // 7 = Mirror horizontal and rotate 90 CW + case 8: + checkWidth = property.Height.Value; + checkHeight = property.Width.Value; + break; // 8 = Rotate 270 CW + default: + checkWidth = property.Width.Value; + checkHeight = property.Height.Value; + break; + } + results.Add(original, new int[] { checkWidth, checkHeight, orientation }); + foreach (string validResolution in _ValidResolutions) + { + desired = GetCollection(validResolution); + desiredWidth = desired[0]; + desiredHeight = desired[1]; + if (checkWidth <= desiredWidth && checkHeight <= desiredHeight) + results.Add(validResolution, new int[] { checkWidth, checkHeight, orientation }); + else + { + if (desiredWidth != desiredHeight) + { + if (checkWidth * desiredHeight > desiredWidth * checkHeight) + results.Add(validResolution, new int[] { desiredWidth, Convert.ToInt32(desiredWidth * checkHeight / (double)checkWidth), orientation }); + else + results.Add(validResolution, new int[] { Convert.ToInt32(desiredHeight * checkWidth / (double)checkHeight), desiredHeight, orientation }); + } + else + { + if (checkWidth * desiredHeight <= desiredWidth * checkHeight) + results.Add(validResolution, new int[] { desiredWidth, desiredHeight, orientation, desiredWidth, Convert.ToInt32(desiredWidth * checkHeight / (double)checkWidth) }); + else + results.Add(validResolution, new int[] { desiredWidth, desiredHeight, orientation, Convert.ToInt32(desiredHeight * checkWidth / (double)checkHeight), desiredHeight }); + } + } + } + return results; + } + + public Dictionary GetResizeKeyValuePairs(List> subFileTuples, List parseExceptions, string original, List> metadataCollection, A_Property property, string subFile, string relativePath, string fileNameWithoutExtension) + { + Dictionary results; + string json; + string[] changesFrom = new string[] { nameof(A_Property), nameof(B_Metadata) }; + List dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); + FileInfo fileInfo = new(Path.Combine(AngleBracketCollection[0].Replace("<>", "{}"), string.Concat(fileNameWithoutExtension, ".json"))); + if (!fileInfo.Exists) + { + if (fileInfo.Directory?.Parent is null) + throw new Exception(); + string parentCheck = Path.Combine(fileInfo.Directory.Parent.FullName, fileInfo.Name); + if (File.Exists(parentCheck)) + { + File.Move(parentCheck, fileInfo.FullName); + fileInfo.Refresh(); + } + } + if (_ForceResizeLastWriteTimeToCreationTime && !fileInfo.Exists && File.Exists(Path.ChangeExtension(fileInfo.FullName, ".delete"))) + { + File.Move(Path.ChangeExtension(fileInfo.FullName, ".delete"), fileInfo.FullName); + fileInfo.Refresh(); + } + if (_ForceResizeLastWriteTimeToCreationTime && fileInfo.Exists && fileInfo.LastWriteTime != fileInfo.CreationTime) + { + File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime); + fileInfo.Refresh(); + } + if (_PropertiesChangedForResize) + results = new(); + else if (!fileInfo.Exists) + results = new(); + else if (dateTimes.Any() && dateTimes.Max() > fileInfo.LastWriteTime) + results = new(); + else + { + json = File.ReadAllText(fileInfo.FullName); + try + { + Dictionary? keyValuePairs; + keyValuePairs = JsonSerializer.Deserialize>(json); + if (keyValuePairs is null) + throw new Exception(); + results = keyValuePairs; + if ((from l in results where l.Value[0] == l.Value[1] select true).Any()) + { + results = GetImageResizes(metadataCollection, property, original); + if (!(from l in results where l.Value[0] == l.Value[1] select true).Any()) + throw new Exception("Was square!"); + } + subFileTuples.Add(new Tuple(nameof(C_Resize), fileInfo.LastWriteTime)); + } + catch (Exception) + { + results = new(); + parseExceptions.Add(nameof(C_Resize)); + } + } + if (results is null || !results.Any()) + { + results = GetImageResizes(metadataCollection, property, original); + json = JsonSerializer.Serialize(results, _WriteIndentedJsonSerializerOptions); + if (Property.Models.Stateless.IPath.WriteAllText(fileInfo.FullName, json, compareBeforeWrite: true)) + { + if (!_ForceResizeLastWriteTimeToCreationTime && (!fileInfo.Exists || fileInfo.LastWriteTime == fileInfo.CreationTime)) + subFileTuples.Add(new Tuple(nameof(C_Resize), DateTime.Now)); + else + { + File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime); + fileInfo.Refresh(); + subFileTuples.Add(new Tuple(nameof(C_Resize), fileInfo.CreationTime)); + } + } + } + return results; + } + +} \ No newline at end of file diff --git a/Resize/Resize.csproj b/Resize/Resize.csproj new file mode 100644 index 0000000..8a82d84 --- /dev/null +++ b/Resize/Resize.csproj @@ -0,0 +1,49 @@ + + + enable + 10.0 + enable + library + win-x64 + net6.0 + + + Phares.View.by.Distance.Resize + false + 5.0.402.104 + Mike Phares + Phares + true + snupkg + + + true + true + true + + + Windows + + + OSX + + + Linux + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Shared/.vscode/settings.json b/Shared/.vscode/settings.json new file mode 100644 index 0000000..a4e70a9 --- /dev/null +++ b/Shared/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "cSpell.words": [ + "Phares" + ] +} \ No newline at end of file diff --git a/Shared/Models/%ClassName%.cs .ai b/Shared/Models/%ClassName%.cs .ai new file mode 100644 index 0000000..e69de29 diff --git a/Shared/Models/Console.cs b/Shared/Models/Console.cs new file mode 100644 index 0000000..d01164f --- /dev/null +++ b/Shared/Models/Console.cs @@ -0,0 +1,27 @@ +using System.Text.Json; +using View_by_Distance.Shared.Models.Methods; + +namespace View_by_Distance.Shared.Models; + +public class Console : Properties.IConsole, IConsole +{ + + ConsoleKey IConsole.ReadKey() + { + ConsoleKey result = System.Console.ReadKey().Key; + return result; + } + + string? IConsole.ReadLine() + { + string? result = System.Console.ReadLine(); + return result; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/Shared/Models/DirectoryFileSystem.cs b/Shared/Models/DirectoryFileSystem.cs new file mode 100644 index 0000000..2693242 --- /dev/null +++ b/Shared/Models/DirectoryFileSystem.cs @@ -0,0 +1,46 @@ +using System.Text.Json; +using System.Text.Json.Serialization; +using View_by_Distance.Shared.Models.Methods; + +namespace View_by_Distance.Shared.Models; + +public class DirectoryFileSystem : Models.FileSystem, Properties.IDirectoryFileSystem, IDirectoryFileSystem +{ + + // protected new string _ClassName; + // protected new string _DataDisplayFileName; + // protected new string _DataFullFileName; + // protected new string _Display; + // protected new DateTime _LastModified; + // public new string ClassName => _ClassName; + // public new string DataDisplayFileName => _DataDisplayFileName; + // public new string DataFullFileName => _DataFullFileName; + // public new string Display => _Display; + // public new DateTime LastModified => _LastModified; + + [JsonConstructor] + public DirectoryFileSystem(string className, string dataDisplayFileName, string dataFullFileName, string display, DateTime lastModified) : base(className, dataDisplayFileName, dataFullFileName, display, lastModified) + { + _ClassName = className; + _DataDisplayFileName = dataDisplayFileName; + _DataFullFileName = dataFullFileName; + _Display = display; + _LastModified = lastModified; + } + + internal DirectoryFileSystem(DirectoryInfo directoryInfo) : base(string.Empty, string.Empty, string.Empty, string.Empty, DateTime.MinValue) + { + _ClassName = "directory"; + _DataDisplayFileName = directoryInfo.Name; + _DataFullFileName = directoryInfo.FullName; + _Display = directoryInfo.Name; + _LastModified = directoryInfo.LastWriteTime; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/Shared/Models/Face.cs b/Shared/Models/Face.cs new file mode 100644 index 0000000..c6945fb --- /dev/null +++ b/Shared/Models/Face.cs @@ -0,0 +1,57 @@ +using System.Text.Json; +using System.Text.Json.Serialization; +using View_by_Distance.Shared.Models.Methods; + +namespace View_by_Distance.Shared.Models; + +public class Face : Properties.IFace, IFace +{ + + protected double? _Α; + protected DateTime _DateTime; + protected Models.FaceEncoding _FaceEncoding; + protected Dictionary _FaceLandmarks; + protected Models.OutputResolution _OutputResolution; + protected Models.Location _Location; + protected int? _LocationIndex; + protected bool _Populated; + protected string _RelativePath; + public double? α => _Α; + public DateTime DateTime => _DateTime; + public Models.FaceEncoding FaceEncoding => _FaceEncoding; + public Dictionary FaceLandmarks => _FaceLandmarks; + public Models.OutputResolution OutputResolution => _OutputResolution; + public Models.Location Location => _Location; + public int? LocationIndex => _LocationIndex; + public bool Populated => _Populated; + public string RelativePath => _RelativePath; + + [JsonConstructor] + public Face(double? α, DateTime dateTime, View_by_Distance.Shared.Models.FaceEncoding faceEncoding, Dictionary faceLandmarks, Models.OutputResolution outputResolution, View_by_Distance.Shared.Models.Location location, int? locationIndex, bool populated, string relativePath) + { + _Α = α; + _DateTime = dateTime; + _FaceEncoding = faceEncoding; + _FaceLandmarks = faceLandmarks; + _Location = location; + _LocationIndex = locationIndex; + _OutputResolution = outputResolution; + _Populated = populated; + _RelativePath = relativePath; + } + + double Stateless.Methods.IFace.TestStatic_Getα(int x1, int x2, int y1, int y2) => throw new NotImplementedException(); + + string Stateless.Methods.IFace.TestStatic_GetJson(string jsonFileFullName) => throw new NotImplementedException(); + + Face Stateless.Methods.IFace.TestStatic_GetFace(string jsonFileFullName) => throw new NotImplementedException(); + + Face[] Stateless.Methods.IFace.TestStatic_GetFaces(string jsonFileFullName) => throw new NotImplementedException(); + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/Shared/Models/FaceEncoding.cs b/Shared/Models/FaceEncoding.cs new file mode 100644 index 0000000..0afa974 --- /dev/null +++ b/Shared/Models/FaceEncoding.cs @@ -0,0 +1,28 @@ +using System.Text.Json; +using System.Text.Json.Serialization; +using View_by_Distance.Shared.Models.Methods; + +namespace View_by_Distance.Shared.Models; + +public class FaceEncoding : Properties.IFaceEncoding, IFaceEncoding +{ + + protected double[] _RawEncoding; + protected int _Size; + public double[] RawEncoding => _RawEncoding; + public int Size => _Size; + + [JsonConstructor] + public FaceEncoding(double[] rawEncoding, int size) + { + _RawEncoding = rawEncoding; + _Size = size; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/Shared/Models/FaceFileSystem.cs b/Shared/Models/FaceFileSystem.cs new file mode 100644 index 0000000..562d1e8 --- /dev/null +++ b/Shared/Models/FaceFileSystem.cs @@ -0,0 +1,226 @@ +using System.Text.Json; +using System.Text.Json.Serialization; +using View_by_Distance.Shared.Models.Methods; + +namespace View_by_Distance.Shared.Models; + +public class FaceFileSystem : Models.FileSystem, Properties.IFaceFileSystem, IFaceFileSystem +{ + + // protected new string _ClassName; + protected string _Confidence; + // protected new string _DataDisplayFileName; + // protected new string _DataFullFileName; + // protected new string _Display; + protected int? _FaceBottom; + protected string _FaceFullFileName; + protected int? _FaceHeight; + protected int? _FaceLeft; + protected string _FaceRelativePath; + protected int? _FaceRight; + protected int? _FaceTop; + protected int? _FaceWidth; + protected int _ImageHeight; + protected int _ImageWidth; + // protected new DateTime _LastModified; + protected string _LocationDisplayIndex; + protected int? _LocationIndex; + protected bool? _Populated; + protected string _RelativePath; + protected string _SourceFullFileName; + protected string _SourceRelativePath; + protected long? _SourceSize; + // public new string ClassName => _ClassName; + public string Confidence => _Confidence; + // public new string DataDisplayFileName => _DataDisplayFileName; + // public new string DataFullFileName => _DataFullFileName; + // public new string Display => _Display; + public int? FaceBottom => _FaceBottom; + public string FaceFullFileName => _FaceFullFileName; + public int? FaceHeight => _FaceHeight; + public int? FaceLeft => _FaceLeft; + public string FaceRelativePath => _FaceRelativePath; + public int? FaceRight => _FaceRight; + public int? FaceTop => _FaceTop; + public int? FaceWidth => _FaceWidth; + public int ImageHeight => _ImageHeight; + public int ImageWidth => _ImageWidth; + // public new DateTime LastModified => _LastModified; + public string LocationDisplayIndex => _LocationDisplayIndex; + public int? LocationIndex => _LocationIndex; + public bool? Populated => _Populated; + public string RelativePath => _RelativePath; + public string SourceFullFileName => _SourceFullFileName; + public string SourceRelativePath => _SourceRelativePath; + public long? SourceSize => _SourceSize; + + [JsonConstructor] + public FaceFileSystem(string className, string confidence, string dataDisplayFileName, string dataFullFileName, string display, int? faceBottom, string faceFullFileName, int? faceHeight, int? faceLeft, string faceRelativePath, int? faceRight, int? faceTop, int? faceWidth, int imageHeight, int imageWidth, DateTime lastModified, string locationDisplayIndex, int? locationIndex, bool? populated, string relativePath, string sourceFullFileName, string sourceRelativePath, long? sourceSize) : base(className, dataDisplayFileName, dataFullFileName, display, lastModified) + { + _Confidence = confidence; + _FaceBottom = faceBottom; + _FaceFullFileName = faceFullFileName; + _FaceHeight = faceHeight; + _FaceLeft = faceLeft; + _FaceRelativePath = faceRelativePath; + _FaceRight = faceRight; + _FaceTop = faceTop; + _FaceWidth = faceWidth; + _ImageHeight = imageHeight; + _ImageWidth = imageWidth; + _LocationDisplayIndex = locationDisplayIndex; + _LocationIndex = locationIndex; + _Populated = populated; + _RelativePath = relativePath; + _SourceFullFileName = sourceFullFileName; + _SourceRelativePath = sourceRelativePath; + _SourceSize = sourceSize; + } + + internal FaceFileSystem(string requestPath, int rootResultsDirectoryAbsoluteUriLength, string cResizeContent, string dFacesContentDirectory, string dataFullFileName, Face face) : base(string.Empty, string.Empty, dataFullFileName, string.Empty, DateTime.MinValue) + { + string confidence; + int? faceBottom; + int? faceHeight; + int? faceLeft; + int? faceRight; + int? faceTop; + int? faceWidth; + int imageHeight; + int imageWidth; + string locationDisplayIndex; + int locationIndex; + long sourceSize; + if (face.LocationIndex is null) + { + locationIndex = 0; + locationDisplayIndex = "01"; + } + else + { + locationIndex = face.LocationIndex.Value; + locationDisplayIndex = (face.LocationIndex.Value + 1).ToString("00"); + } + if (face.Location is null) + { + faceTop = null; + faceLeft = null; + faceRight = null; + faceWidth = null; + faceBottom = null; + faceHeight = null; + confidence = "0"; + } + else + { + faceTop = face.Location.Top; + faceLeft = face.Location.Left; + faceRight = face.Location.Right; + faceBottom = face.Location.Bottom; + faceWidth = face.Location.Right - face.Location.Left; + faceHeight = face.Location.Bottom - face.Location.Top; + confidence = face.Location.Confidence.ToString("00.000"); + } + string? directoryName = Path.GetDirectoryName(face.RelativePath); + string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(face.RelativePath); + string sourceFullFileName = string.Concat(cResizeContent, face.RelativePath); + if (directoryName is null) + throw new Exception(); + string faceFullFileName = string.Concat(dFacesContentDirectory, Path.Combine(directoryName, fileNameWithoutExtension, $"{locationIndex} - {fileNameWithoutExtension}.png")); + string faceRelativePath = string.Concat(requestPath, new Uri(faceFullFileName).AbsoluteUri[rootResultsDirectoryAbsoluteUriLength..]); + string sourceRelativePath = string.Concat(requestPath, new Uri(sourceFullFileName).AbsoluteUri[rootResultsDirectoryAbsoluteUriLength..]); + FileInfo fileInfo = new(sourceFullFileName); + if (face.Populated && !File.Exists(faceFullFileName)) + Stateless.Methods.IFaceFileSystem.SearchForMissingFile(faceFullFileName, fileInfo: new FileInfo(string.Empty), dataFullFileName); + if (!fileInfo.Exists) + { + sourceSize = 0; + if (face.OutputResolution is null) + { + imageWidth = 0; + imageHeight = 0; + } + else + { + imageWidth = face.OutputResolution.Width; + imageHeight = face.OutputResolution.Height; + } + Stateless.Methods.IFaceFileSystem.SearchForMissingFile(fileInfo.FullName, fileInfo, dataFullFileName); + } + else + { + sourceSize = fileInfo.Length; + if (face.OutputResolution is not null) + { + imageWidth = face.OutputResolution.Width; + imageHeight = face.OutputResolution.Height; + } + else + { + System.Drawing.Size size = Stateless.Methods.ImageHelper.GetDimensions(fileInfo.FullName, faceRight, faceBottom); + imageWidth = size.Width; + imageHeight = size.Height; + } + } + _ClassName = "file"; + _FaceBottom = faceBottom; + _Confidence = confidence; + _DataDisplayFileName = Path.GetFileName(dataFullFileName); + _DataFullFileName = dataFullFileName; + _Display = string.Concat(locationDisplayIndex, " - ", Path.GetFileName(sourceFullFileName)); + _FaceFullFileName = faceFullFileName; + _FaceRelativePath = faceRelativePath; + _FaceHeight = faceHeight; + _ImageHeight = imageHeight; + _LastModified = face.DateTime; + _FaceLeft = faceLeft; + _LocationDisplayIndex = locationDisplayIndex; + _LocationIndex = face.LocationIndex; + _Populated = face.Populated; + _RelativePath = string.Empty; + _FaceRight = faceRight; + _SourceFullFileName = sourceFullFileName; + _SourceRelativePath = sourceRelativePath; + _SourceSize = sourceSize; + _FaceTop = faceTop; + _FaceWidth = faceWidth; + _ImageWidth = imageWidth; + } + + string IFileSystem.GetDate() + { + string result = _LastModified.ToString("MM/dd/yyyy hh:mm:ss tt"); + return result; + } + + string IFaceFileSystem.GetSize() + { + string result; + if (_SourceSize is null) + result = string.Empty; + else + { + int order = 0; + double len = _SourceSize.Value; + string[] sizes = { "B", "KB", "MB", "GB", "TB" }; + while (len >= 1024 && order < sizes.Length - 1) + { + order++; + len /= 1024; + } + result = String.Format("{0:0.##} {1}", len, sizes[order]); + } + return result; + } + + void Stateless.Methods.IFaceFileSystem.TestStatic_SearchForMissingFile(string fullFileName, FileInfo fileInfo, string dataFullFileName) => throw new NotImplementedException(); + + FaceFileSystem[][] Stateless.Methods.IFaceFileSystem.TestStatic_GetFaceFileSystemCollection(string requestPath, string rootResultsDirectory, (string RootResultsDirectoryAbsoluteUri, string C_ResizeContentDirectory, string D_FacesContentDirectory, string E_DistanceCollectionDirectory) tuple, string selectedFileFullName) => throw new NotImplementedException(); + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/Shared/Models/FacePoint.cs b/Shared/Models/FacePoint.cs new file mode 100644 index 0000000..d7a7381 --- /dev/null +++ b/Shared/Models/FacePoint.cs @@ -0,0 +1,31 @@ +using System.Text.Json; +using System.Text.Json.Serialization; +using View_by_Distance.Shared.Models.Methods; + +namespace View_by_Distance.Shared.Models; + +public class FacePoint : Properties.IFacePoint, IFacePoint +{ + + protected int _Index; + protected int _X; + protected int _Y; + public int Index => _Index; + public int X => _X; + public int Y => _Y; + + [JsonConstructor] + public FacePoint(int index, int x, int y) + { + _Index = index; + _X = x; + _Y = y; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/Shared/Models/FileSystem.cs b/Shared/Models/FileSystem.cs new file mode 100644 index 0000000..4cd728c --- /dev/null +++ b/Shared/Models/FileSystem.cs @@ -0,0 +1,54 @@ +using System.Text.Json; +using System.Text.Json.Serialization; +using View_by_Distance.Shared.Models.Methods; + +namespace View_by_Distance.Shared.Models; + +public class FileSystem : Properties.IFileSystem, IFileSystem +{ + + protected string _ClassName; + protected string _DataDisplayFileName; + protected string _DataFullFileName; + protected string _Display; + protected DateTime _LastModified; + public string ClassName => _ClassName; + public string DataDisplayFileName => _DataDisplayFileName; + public string DataFullFileName => _DataFullFileName; + public string Display => _Display; + public DateTime LastModified => _LastModified; + + [JsonConstructor] + public FileSystem(string className, string dataDisplayFileName, string dataFullFileName, string display, DateTime lastModified) + { + _ClassName = className; + _DataDisplayFileName = dataDisplayFileName; + _DataFullFileName = dataFullFileName; + _Display = display; + _LastModified = lastModified; + } + + public FileSystem(string dataFullFileName, Exception ex) + { + _ClassName = string.Empty; + _DataDisplayFileName = string.Empty; + _DataFullFileName = dataFullFileName; + _Display = string.Concat(ex.Message, Environment.NewLine, ex.StackTrace, Environment.NewLine, dataFullFileName); + _LastModified = DateTime.Now; + } + + string IFileSystem.GetDate() + { + string result = _LastModified.ToString("MM/dd/yyyy hh:mm:ss tt"); + return result; + } + + List Stateless.Methods.IFileSystem.TestStatic_GetFileSystemCollection(string requestPath, string rootResultsDirectory, (string RootResultsDirectoryAbsoluteUri, string C_ResizeContentDirectory, string D_FacesContentDirectory, string E_DistanceCollectionDirectory) tuple, string[] directories, string[] files, bool all) => throw new NotImplementedException(); + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/Shared/Models/Location.cs b/Shared/Models/Location.cs new file mode 100644 index 0000000..12e4c1b --- /dev/null +++ b/Shared/Models/Location.cs @@ -0,0 +1,37 @@ +using System.Text.Json; +using System.Text.Json.Serialization; +using View_by_Distance.Shared.Models.Methods; + +namespace View_by_Distance.Shared.Models; + +public class Location : Properties.ILocation, ILocation +{ + + protected double _Confidence; + protected int _Bottom; + protected int _Left; + protected int _Right; + protected int _Top; + public double Confidence => _Confidence; + public int Bottom => _Bottom; + public int Left => _Left; + public int Right => _Right; + public int Top => _Top; + + [JsonConstructor] + public Location(double confidence, int bottom, int left, int right, int top) + { + _Confidence = confidence; + _Bottom = bottom; + _Left = left; + _Right = right; + _Top = top; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/Shared/Models/MetadataFile.cs b/Shared/Models/MetadataFile.cs new file mode 100644 index 0000000..b8f8385 --- /dev/null +++ b/Shared/Models/MetadataFile.cs @@ -0,0 +1,32 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class MetadataFile : Properties.IMetadataFile +{ + + protected readonly MetadataFileId _Id; // {-_-}SingletonClass + protected readonly MetadataFileCollection _Collection; // {-_-}SingletonClass + + public MetadataFileId Id => _Id; // {-_-}SingletonClass + public MetadataFileCollection Collection => _Collection; // {-_-}SingletonClass + + [JsonConstructor] + public MetadataFile + ( + MetadataFileId id, + MetadataFileCollection collection + ) + { + _Id = id; // {-_-}SingletonClass + _Collection = collection; // {-_-}SingletonClass + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } // ... + +} \ No newline at end of file diff --git a/Shared/Models/MetadataFileCollection.cs b/Shared/Models/MetadataFileCollection.cs new file mode 100644 index 0000000..c6ccabd --- /dev/null +++ b/Shared/Models/MetadataFileCollection.cs @@ -0,0 +1,25 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class MetadataFileCollection : Properties.IMetadataFileCollection +{ + + protected readonly Dictionary>> _Values; // {{1}}SingletonValue + + public Dictionary>> Values => _Values; // {{1}}SingletonValue + + [JsonConstructor] + public MetadataFileCollection + ( + Dictionary>> values + ) => _Values = values; // {{1}}SingletonValue + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } // ... + +} \ No newline at end of file diff --git a/Shared/Models/MetadataFileId.cs b/Shared/Models/MetadataFileId.cs new file mode 100644 index 0000000..fb9106a --- /dev/null +++ b/Shared/Models/MetadataFileId.cs @@ -0,0 +1,25 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class MetadataFileId : Properties.IMetadataFileId +{ + + protected readonly string _Value; // {{1}}SingletonValue + + public string Value => _Value; // {{1}}SingletonValue + + [JsonConstructor] + public MetadataFileId + ( + string value + ) => _Value = value; // {{1}}SingletonValue + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } // ... + +} \ No newline at end of file diff --git a/Shared/Models/Methods/I%ClassName%.cs .ai b/Shared/Models/Methods/I%ClassName%.cs .ai new file mode 100644 index 0000000..e69de29 diff --git a/Shared/Models/Methods/IBackground.cs b/Shared/Models/Methods/IBackground.cs new file mode 100644 index 0000000..de0d7cd --- /dev/null +++ b/Shared/Models/Methods/IBackground.cs @@ -0,0 +1,12 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IBackground +{ + + void Update(); + void Dispose(); + List DoBackup(); + void Stop(bool immediate); + void Catch(Exception exception); + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IConfiguration.cs b/Shared/Models/Methods/IConfiguration.cs new file mode 100644 index 0000000..f6217ce --- /dev/null +++ b/Shared/Models/Methods/IConfiguration.cs @@ -0,0 +1,6 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IConfiguration +{ + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IConsole.cs b/Shared/Models/Methods/IConsole.cs new file mode 100644 index 0000000..0859e23 --- /dev/null +++ b/Shared/Models/Methods/IConsole.cs @@ -0,0 +1,9 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IConsole +{ + + string? ReadLine(); + ConsoleKey ReadKey(); + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IFace.cs b/Shared/Models/Methods/IFace.cs new file mode 100644 index 0000000..e1015cf --- /dev/null +++ b/Shared/Models/Methods/IFace.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IFace : Stateless.Methods.IFace +{ // ... + + // + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IFaceEncoding.cs b/Shared/Models/Methods/IFaceEncoding.cs new file mode 100644 index 0000000..899e31d --- /dev/null +++ b/Shared/Models/Methods/IFaceEncoding.cs @@ -0,0 +1,6 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IFaceEncoding +{ + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IFaceFileSystem.cs b/Shared/Models/Methods/IFaceFileSystem.cs new file mode 100644 index 0000000..768f34a --- /dev/null +++ b/Shared/Models/Methods/IFaceFileSystem.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IFaceFileSystem : Stateless.Methods.IFaceFileSystem, IFileSystem +{ + + string GetSize(); + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IFacePoint.cs b/Shared/Models/Methods/IFacePoint.cs new file mode 100644 index 0000000..394b05e --- /dev/null +++ b/Shared/Models/Methods/IFacePoint.cs @@ -0,0 +1,6 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IFacePoint +{ + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IFileSystem.cs b/Shared/Models/Methods/IFileSystem.cs new file mode 100644 index 0000000..a96115d --- /dev/null +++ b/Shared/Models/Methods/IFileSystem.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IFileSystem : Stateless.Methods.IFileSystem +{ + + string GetDate(); + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IIdentify.cs b/Shared/Models/Methods/IIdentify.cs new file mode 100644 index 0000000..db60129 --- /dev/null +++ b/Shared/Models/Methods/IIdentify.cs @@ -0,0 +1,6 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IIdentify +{ + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IIndex.cs b/Shared/Models/Methods/IIndex.cs new file mode 100644 index 0000000..0c30d30 --- /dev/null +++ b/Shared/Models/Methods/IIndex.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IIndex : Stateless.Methods.IIndex +{ // ... + + // + +} \ No newline at end of file diff --git a/Shared/Models/Methods/ILocation.cs b/Shared/Models/Methods/ILocation.cs new file mode 100644 index 0000000..e637192 --- /dev/null +++ b/Shared/Models/Methods/ILocation.cs @@ -0,0 +1,6 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface ILocation +{ + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IMetadataFile.cs b/Shared/Models/Methods/IMetadataFile.cs new file mode 100644 index 0000000..449e4ae --- /dev/null +++ b/Shared/Models/Methods/IMetadataFile.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IMetadataFile : Stateless.Methods.IMetadataFile +{ + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IMetadataFileCollection.cs b/Shared/Models/Methods/IMetadataFileCollection.cs new file mode 100644 index 0000000..7f8da4b --- /dev/null +++ b/Shared/Models/Methods/IMetadataFileCollection.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IMetadataFileCollection : Stateless.Methods.IMetadataFileCollection +{ + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IMetadataFileId.cs b/Shared/Models/Methods/IMetadataFileId.cs new file mode 100644 index 0000000..8c1280a --- /dev/null +++ b/Shared/Models/Methods/IMetadataFileId.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IMetadataFileId : Stateless.Methods.IMetadataFileId +{ + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Methods/INavigate.cs b/Shared/Models/Methods/INavigate.cs new file mode 100644 index 0000000..99ba9f5 --- /dev/null +++ b/Shared/Models/Methods/INavigate.cs @@ -0,0 +1,6 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface INavigate +{ + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IOutputResolution.cs b/Shared/Models/Methods/IOutputResolution.cs new file mode 100644 index 0000000..2b7d3b9 --- /dev/null +++ b/Shared/Models/Methods/IOutputResolution.cs @@ -0,0 +1,6 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IOutputResolution +{ + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IPerson.cs b/Shared/Models/Methods/IPerson.cs new file mode 100644 index 0000000..ba3d053 --- /dev/null +++ b/Shared/Models/Methods/IPerson.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IPerson : Stateless.Methods.IPerson +{ + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IPersonAddress.cs b/Shared/Models/Methods/IPersonAddress.cs new file mode 100644 index 0000000..4f982c7 --- /dev/null +++ b/Shared/Models/Methods/IPersonAddress.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IPersonAddress : Stateless.Methods.IPersonAddress +{ + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IPersonAddressCity.cs b/Shared/Models/Methods/IPersonAddressCity.cs new file mode 100644 index 0000000..074d800 --- /dev/null +++ b/Shared/Models/Methods/IPersonAddressCity.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IPersonAddressCity : Stateless.Methods.IPersonAddressCity +{ + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IPersonAddressState.cs b/Shared/Models/Methods/IPersonAddressState.cs new file mode 100644 index 0000000..5fef12a --- /dev/null +++ b/Shared/Models/Methods/IPersonAddressState.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IPersonAddressState : Stateless.Methods.IPersonAddressState +{ + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IPersonAddressStreet.cs b/Shared/Models/Methods/IPersonAddressStreet.cs new file mode 100644 index 0000000..c33151c --- /dev/null +++ b/Shared/Models/Methods/IPersonAddressStreet.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IPersonAddressStreet : Stateless.Methods.IPersonAddressStreet +{ + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IPersonAddressZipCode.cs b/Shared/Models/Methods/IPersonAddressZipCode.cs new file mode 100644 index 0000000..81db822 --- /dev/null +++ b/Shared/Models/Methods/IPersonAddressZipCode.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IPersonAddressZipCode : Stateless.Methods.IPersonAddressZipCode +{ + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IPersonBirthday.cs b/Shared/Models/Methods/IPersonBirthday.cs new file mode 100644 index 0000000..93f99f0 --- /dev/null +++ b/Shared/Models/Methods/IPersonBirthday.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IPersonBirthday : Stateless.Methods.IPersonBirthday +{ + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IPersonComment.cs b/Shared/Models/Methods/IPersonComment.cs new file mode 100644 index 0000000..22ee910 --- /dev/null +++ b/Shared/Models/Methods/IPersonComment.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IPersonComment : Stateless.Methods.IPersonComment +{ + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IPersonEmail.cs b/Shared/Models/Methods/IPersonEmail.cs new file mode 100644 index 0000000..161461b --- /dev/null +++ b/Shared/Models/Methods/IPersonEmail.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IPersonEmail : Stateless.Methods.IPersonEmail +{ + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IPersonId.cs b/Shared/Models/Methods/IPersonId.cs new file mode 100644 index 0000000..3afac02 --- /dev/null +++ b/Shared/Models/Methods/IPersonId.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IPersonId : Stateless.Methods.IPersonId +{ + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IPersonName.cs b/Shared/Models/Methods/IPersonName.cs new file mode 100644 index 0000000..f31505a --- /dev/null +++ b/Shared/Models/Methods/IPersonName.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IPersonName : Stateless.Methods.IPersonName +{ + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IPersonNameAlias.cs b/Shared/Models/Methods/IPersonNameAlias.cs new file mode 100644 index 0000000..e86637f --- /dev/null +++ b/Shared/Models/Methods/IPersonNameAlias.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IPersonNameAlias : Stateless.Methods.IPersonNameAlias +{ + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IPersonNameFirst.cs b/Shared/Models/Methods/IPersonNameFirst.cs new file mode 100644 index 0000000..0b8e170 --- /dev/null +++ b/Shared/Models/Methods/IPersonNameFirst.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IPersonNameFirst : Stateless.Methods.IPersonNameFirst +{ + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IPersonNameLast.cs b/Shared/Models/Methods/IPersonNameLast.cs new file mode 100644 index 0000000..f33ecf3 --- /dev/null +++ b/Shared/Models/Methods/IPersonNameLast.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IPersonNameLast : Stateless.Methods.IPersonNameLast +{ + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IPersonNameMiddle.cs b/Shared/Models/Methods/IPersonNameMiddle.cs new file mode 100644 index 0000000..3bac1af --- /dev/null +++ b/Shared/Models/Methods/IPersonNameMiddle.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IPersonNameMiddle : Stateless.Methods.IPersonNameMiddle +{ + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IPersonNumber.cs b/Shared/Models/Methods/IPersonNumber.cs new file mode 100644 index 0000000..8194503 --- /dev/null +++ b/Shared/Models/Methods/IPersonNumber.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IPersonNumber : Stateless.Methods.IPersonNumber +{ + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IPersonURL.cs b/Shared/Models/Methods/IPersonURL.cs new file mode 100644 index 0000000..30d5fa5 --- /dev/null +++ b/Shared/Models/Methods/IPersonURL.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IPersonURL : Stateless.Methods.IPersonURL +{ + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IProperty.cs b/Shared/Models/Methods/IProperty.cs new file mode 100644 index 0000000..4c88ca4 --- /dev/null +++ b/Shared/Models/Methods/IProperty.cs @@ -0,0 +1,6 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IProperty +{ + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IRelativePaths.cs b/Shared/Models/Methods/IRelativePaths.cs new file mode 100644 index 0000000..a855ed8 --- /dev/null +++ b/Shared/Models/Methods/IRelativePaths.cs @@ -0,0 +1,6 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IRelativePaths +{ + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IStorage.cs b/Shared/Models/Methods/IStorage.cs new file mode 100644 index 0000000..bc09868 --- /dev/null +++ b/Shared/Models/Methods/IStorage.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IStorage : Stateless.Methods.IStorage +{ + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Navigate.cs b/Shared/Models/Navigate.cs new file mode 100644 index 0000000..4a4090f --- /dev/null +++ b/Shared/Models/Navigate.cs @@ -0,0 +1,39 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class Navigate : Properties.INavigate +{ + + protected List _Levels; + protected string _SourceDirectory; + protected string _DirectoryRelativePath; + protected string _EncodedSourceDirectory; + protected Models.FaceFileSystem[] _FaceFileSystemCollection; + protected Models.DirectoryFileSystem[] _DirectoryFileSystemCollection; + public List Levels => _Levels; + public string SourceDirectory => _SourceDirectory; + public string DirectoryRelativePath => _DirectoryRelativePath; + public string EncodedSourceDirectory => _EncodedSourceDirectory; + public Models.FaceFileSystem[] FaceFileSystemCollection => _FaceFileSystemCollection; + public Models.DirectoryFileSystem[] DirectoryFileSystemCollection => _DirectoryFileSystemCollection; + + [JsonConstructor] + public Navigate(List levels, string sourceDirectory, string directoryRelativePath, string encodedSourceDirectory, Models.FaceFileSystem[] faceFileSystemCollection, Models.DirectoryFileSystem[] directoryFileSystemCollection) + { + _Levels = levels; + _SourceDirectory = sourceDirectory; + _DirectoryRelativePath = directoryRelativePath; + _EncodedSourceDirectory = encodedSourceDirectory; + _FaceFileSystemCollection = faceFileSystemCollection; + _DirectoryFileSystemCollection = directoryFileSystemCollection; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/Shared/Models/OutputResolution.cs b/Shared/Models/OutputResolution.cs new file mode 100644 index 0000000..e88d8f2 --- /dev/null +++ b/Shared/Models/OutputResolution.cs @@ -0,0 +1,31 @@ +using System.Text.Json; +using System.Text.Json.Serialization; +using View_by_Distance.Shared.Models.Methods; + +namespace View_by_Distance.Shared.Models; + +public class OutputResolution : Properties.IOutputResolution, IOutputResolution +{ + + protected int _Height; + protected int _Orientation; + protected int _Width; + public int Height => _Height; + public int Orientation => _Orientation; + public int Width => _Width; + + [JsonConstructor] + public OutputResolution(int height, int orientation, int width) + { + _Height = height; + _Orientation = orientation; + _Width = width; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/Shared/Models/Person.cs b/Shared/Models/Person.cs new file mode 100644 index 0000000..5de3fb1 --- /dev/null +++ b/Shared/Models/Person.cs @@ -0,0 +1,56 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class Person : Properties.IPerson +{ + + protected readonly PersonId _Id; // {-_-}SingletonClass + protected readonly PersonBirthday _Birthday; // {-_-}SingletonClass + protected readonly PersonName _Name; // {{_}}JsonValueKindObject + protected readonly List _Comments; // <{_}>PluralClass + protected readonly List _URLs; // <{_}>PluralClass + protected readonly List _Numbers; // <{_}>PluralClass + protected readonly List _Emails; // <{_}>PluralClass + protected readonly List _Addresses; // <<_>>JsonValueKindArray + + public PersonId Id => _Id; // {-_-}SingletonClass + public PersonBirthday Birthday => _Birthday; // {-_-}SingletonClass + public PersonName Name => _Name; // {{_}}JsonValueKindObject + public List Comments => _Comments; // <{_}>PluralClass + public List URLs => _URLs; // <{_}>PluralClass + public List Numbers => _Numbers; // <{_}>PluralClass + public List Emails => _Emails; // <{_}>PluralClass + public List Addresses => _Addresses; // <<_>>JsonValueKindArray + + [JsonConstructor] + public Person + ( + PersonId id, + PersonBirthday birthday, + PersonName name, + List comments, + List uRLs, + List numbers, + List emails, + List addresses + ) + { + _Id = id; // {-_-}SingletonClass + _Birthday = birthday; // {-_-}SingletonClass + _Name = name; // {{_}}JsonValueKindObject + _Comments = comments; // <{_}>PluralClass + _URLs = uRLs; // <{_}>PluralClass + _Numbers = numbers; // <{_}>PluralClass + _Emails = emails; // <{_}>PluralClass + _Addresses = addresses; // <<_>>JsonValueKindArray + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } // ... + +} \ No newline at end of file diff --git a/Shared/Models/PersonAddress.cs b/Shared/Models/PersonAddress.cs new file mode 100644 index 0000000..83e910a --- /dev/null +++ b/Shared/Models/PersonAddress.cs @@ -0,0 +1,40 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class PersonAddress : Properties.IPersonAddress +{ + + protected readonly PersonAddressStreet _Street; // {-_-}SingletonClass + protected readonly PersonAddressCity _City; // {-_-}SingletonClass + protected readonly PersonAddressState _State; // {-_-}SingletonClass + protected readonly PersonAddressZipCode _ZipCode; // {-_-}SingletonClass + + public PersonAddressStreet Street => _Street; // {-_-}SingletonClass + public PersonAddressCity City => _City; // {-_-}SingletonClass + public PersonAddressState State => _State; // {-_-}SingletonClass + public PersonAddressZipCode ZipCode => _ZipCode; // {-_-}SingletonClass + + [JsonConstructor] + public PersonAddress + ( + PersonAddressStreet street, + PersonAddressCity city, + PersonAddressState state, + PersonAddressZipCode zipCode + ) + { + _Street = street; // {-_-}SingletonClass + _City = city; // {-_-}SingletonClass + _State = state; // {-_-}SingletonClass + _ZipCode = zipCode; // {-_-}SingletonClass + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } // ... + +} \ No newline at end of file diff --git a/Shared/Models/PersonAddressCity.cs b/Shared/Models/PersonAddressCity.cs new file mode 100644 index 0000000..a5488ac --- /dev/null +++ b/Shared/Models/PersonAddressCity.cs @@ -0,0 +1,25 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class PersonAddressCity : Properties.IPersonAddressCity +{ + + protected readonly string _Value; // {{1}}SingletonValue + + public string Value => _Value; // {{1}}SingletonValue + + [JsonConstructor] + public PersonAddressCity + ( + string value + ) => _Value = value; // {{1}}SingletonValue + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } // ... + +} \ No newline at end of file diff --git a/Shared/Models/PersonAddressState.cs b/Shared/Models/PersonAddressState.cs new file mode 100644 index 0000000..16d4cd6 --- /dev/null +++ b/Shared/Models/PersonAddressState.cs @@ -0,0 +1,25 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class PersonAddressState : Properties.IPersonAddressState +{ + + protected readonly string _Value; // {{1}}SingletonValue + + public string Value => _Value; // {{1}}SingletonValue + + [JsonConstructor] + public PersonAddressState + ( + string value + ) => _Value = value; // {{1}}SingletonValue + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } // ... + +} \ No newline at end of file diff --git a/Shared/Models/PersonAddressStreet.cs b/Shared/Models/PersonAddressStreet.cs new file mode 100644 index 0000000..35a8162 --- /dev/null +++ b/Shared/Models/PersonAddressStreet.cs @@ -0,0 +1,25 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class PersonAddressStreet : Properties.IPersonAddressStreet +{ + + protected readonly string _Value; // {{1}}SingletonValue + + public string Value => _Value; // {{1}}SingletonValue + + [JsonConstructor] + public PersonAddressStreet + ( + string value + ) => _Value = value; // {{1}}SingletonValue + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } // ... + +} \ No newline at end of file diff --git a/Shared/Models/PersonAddressZipCode.cs b/Shared/Models/PersonAddressZipCode.cs new file mode 100644 index 0000000..98f6423 --- /dev/null +++ b/Shared/Models/PersonAddressZipCode.cs @@ -0,0 +1,25 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class PersonAddressZipCode : Properties.IPersonAddressZipCode +{ + + protected readonly string _Value; // {{1}}SingletonValue + + public string Value => _Value; // {{1}}SingletonValue + + [JsonConstructor] + public PersonAddressZipCode + ( + string value + ) => _Value = value; // {{1}}SingletonValue + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } // ... + +} \ No newline at end of file diff --git a/Shared/Models/PersonBirthday.cs b/Shared/Models/PersonBirthday.cs new file mode 100644 index 0000000..ba26258 --- /dev/null +++ b/Shared/Models/PersonBirthday.cs @@ -0,0 +1,25 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class PersonBirthday : Properties.IPersonBirthday +{ + + protected readonly DateTime _Value; // {{1}}SingletonValue + + public DateTime Value => _Value; // {{1}}SingletonValue + + [JsonConstructor] + public PersonBirthday + ( + DateTime value + ) => _Value = value; // {{1}}SingletonValue + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } // ... + +} \ No newline at end of file diff --git a/Shared/Models/PersonComment.cs b/Shared/Models/PersonComment.cs new file mode 100644 index 0000000..8468802 --- /dev/null +++ b/Shared/Models/PersonComment.cs @@ -0,0 +1,25 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class PersonComment : Properties.IPersonComment +{ + + protected readonly string _Value; // <{1}>PluralValue + + public string Value => _Value; // <{1}>PluralValue + + [JsonConstructor] + public PersonComment + ( + string value + ) => _Value = value; // <{1}>PluralValue + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } // ... + +} \ No newline at end of file diff --git a/Shared/Models/PersonEmail.cs b/Shared/Models/PersonEmail.cs new file mode 100644 index 0000000..1973445 --- /dev/null +++ b/Shared/Models/PersonEmail.cs @@ -0,0 +1,25 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class PersonEmail : Properties.IPersonEmail +{ + + protected readonly string _Value; // <{1}>PluralValue + + public string Value => _Value; // <{1}>PluralValue + + [JsonConstructor] + public PersonEmail + ( + string value + ) => _Value = value; // <{1}>PluralValue + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } // ... + +} \ No newline at end of file diff --git a/Shared/Models/PersonId.cs b/Shared/Models/PersonId.cs new file mode 100644 index 0000000..e064d58 --- /dev/null +++ b/Shared/Models/PersonId.cs @@ -0,0 +1,25 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class PersonId : Properties.IPersonId +{ + + protected readonly long _Value; // {{1}}SingletonValue + + public long Value => _Value; // {{1}}SingletonValue + + [JsonConstructor] + public PersonId + ( + long value + ) => _Value = value; // {{1}}SingletonValue + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } // ... + +} \ No newline at end of file diff --git a/Shared/Models/PersonImport.cs b/Shared/Models/PersonImport.cs new file mode 100644 index 0000000..bc914a7 --- /dev/null +++ b/Shared/Models/PersonImport.cs @@ -0,0 +1,37 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class PersonImport +{ + + public DateTime _Key; + public string _Name; + public string _MergeName; + public string _OldName; + public string _Comment; + + public DateTime Key => _Key; + public string Name => _Name; + public string MergeName => _MergeName; + public string OldName => _OldName; + public string Comment => _Comment; + + [JsonConstructor] + public PersonImport(DateTime key, string name, string mergeName, string oldName, string comment) + { + _Key = key; + _Name = name; + _MergeName = mergeName; + _OldName = oldName; + _Comment = comment; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/Shared/Models/PersonName.cs b/Shared/Models/PersonName.cs new file mode 100644 index 0000000..c71bfe0 --- /dev/null +++ b/Shared/Models/PersonName.cs @@ -0,0 +1,40 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class PersonName : Properties.IPersonName +{ + + protected readonly PersonNameFirst _First; // {-_-}SingletonClass + protected readonly PersonNameMiddle _Middle; // {-_-}SingletonClass + protected readonly PersonNameLast _Last; // {-_-}SingletonClass + protected readonly PersonNameAlias _Alias; // {-_-}SingletonClass + + public PersonNameFirst First => _First; // {-_-}SingletonClass + public PersonNameMiddle Middle => _Middle; // {-_-}SingletonClass + public PersonNameLast Last => _Last; // {-_-}SingletonClass + public PersonNameAlias Alias => _Alias; // {-_-}SingletonClass + + [JsonConstructor] + public PersonName + ( + PersonNameFirst first, + PersonNameMiddle middle, + PersonNameLast last, + PersonNameAlias alias + ) + { + _First = first; // {-_-}SingletonClass + _Middle = middle; // {-_-}SingletonClass + _Last = last; // {-_-}SingletonClass + _Alias = alias; // {-_-}SingletonClass + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } // ... + +} \ No newline at end of file diff --git a/Shared/Models/PersonNameAlias.cs b/Shared/Models/PersonNameAlias.cs new file mode 100644 index 0000000..04b4370 --- /dev/null +++ b/Shared/Models/PersonNameAlias.cs @@ -0,0 +1,25 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class PersonNameAlias : Properties.IPersonNameAlias +{ + + protected readonly string _Value; // {{1}}SingletonValue + + public string Value => _Value; // {{1}}SingletonValue + + [JsonConstructor] + public PersonNameAlias + ( + string value + ) => _Value = value; // {{1}}SingletonValue + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } // ... + +} \ No newline at end of file diff --git a/Shared/Models/PersonNameFirst.cs b/Shared/Models/PersonNameFirst.cs new file mode 100644 index 0000000..d2ae739 --- /dev/null +++ b/Shared/Models/PersonNameFirst.cs @@ -0,0 +1,25 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class PersonNameFirst : Properties.IPersonNameFirst +{ + + protected readonly string _Value; // {{1}}SingletonValue + + public string Value => _Value; // {{1}}SingletonValue + + [JsonConstructor] + public PersonNameFirst + ( + string value + ) => _Value = value; // {{1}}SingletonValue + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } // ... + +} \ No newline at end of file diff --git a/Shared/Models/PersonNameLast.cs b/Shared/Models/PersonNameLast.cs new file mode 100644 index 0000000..db4fb32 --- /dev/null +++ b/Shared/Models/PersonNameLast.cs @@ -0,0 +1,25 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class PersonNameLast : Properties.IPersonNameLast +{ + + protected readonly string _Value; // {{1}}SingletonValue + + public string Value => _Value; // {{1}}SingletonValue + + [JsonConstructor] + public PersonNameLast + ( + string value + ) => _Value = value; // {{1}}SingletonValue + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } // ... + +} \ No newline at end of file diff --git a/Shared/Models/PersonNameMiddle.cs b/Shared/Models/PersonNameMiddle.cs new file mode 100644 index 0000000..65f3ddf --- /dev/null +++ b/Shared/Models/PersonNameMiddle.cs @@ -0,0 +1,25 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class PersonNameMiddle : Properties.IPersonNameMiddle +{ + + protected readonly string _Value; // {{1}}SingletonValue + + public string Value => _Value; // {{1}}SingletonValue + + [JsonConstructor] + public PersonNameMiddle + ( + string value + ) => _Value = value; // {{1}}SingletonValue + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } // ... + +} \ No newline at end of file diff --git a/Shared/Models/PersonNumber.cs b/Shared/Models/PersonNumber.cs new file mode 100644 index 0000000..b742404 --- /dev/null +++ b/Shared/Models/PersonNumber.cs @@ -0,0 +1,25 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class PersonNumber : Properties.IPersonNumber +{ + + protected readonly string _Value; // <{1}>PluralValue + + public string Value => _Value; // <{1}>PluralValue + + [JsonConstructor] + public PersonNumber + ( + string value + ) => _Value = value; // <{1}>PluralValue + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } // ... + +} \ No newline at end of file diff --git a/Shared/Models/PersonURL.cs b/Shared/Models/PersonURL.cs new file mode 100644 index 0000000..d0dcdac --- /dev/null +++ b/Shared/Models/PersonURL.cs @@ -0,0 +1,25 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class PersonURL : Properties.IPersonURL +{ + + protected readonly string _Value; // <{1}>PluralValue + + public string Value => _Value; // <{1}>PluralValue + + [JsonConstructor] + public PersonURL + ( + string value + ) => _Value = value; // <{1}>PluralValue + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } // ... + +} \ No newline at end of file diff --git a/Shared/Models/Properties/I%ClassName%.cs .ai b/Shared/Models/Properties/I%ClassName%.cs .ai new file mode 100644 index 0000000..e69de29 diff --git a/Shared/Models/Properties/IBackground.cs b/Shared/Models/Properties/IBackground.cs new file mode 100644 index 0000000..fa3fcfd --- /dev/null +++ b/Shared/Models/Properties/IBackground.cs @@ -0,0 +1,6 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IBackground +{ + +} \ No newline at end of file diff --git a/Shared/Models/Properties/IBackgroundPage.cs b/Shared/Models/Properties/IBackgroundPage.cs new file mode 100644 index 0000000..af7e855 --- /dev/null +++ b/Shared/Models/Properties/IBackgroundPage.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IBackgroundPage +{ + + public List Exceptions { get; } + public string Message { get; } + public string WorkingDirectory { get; } + +} \ No newline at end of file diff --git a/Shared/Models/Properties/IConfiguration.cs b/Shared/Models/Properties/IConfiguration.cs new file mode 100644 index 0000000..1e7acfc --- /dev/null +++ b/Shared/Models/Properties/IConfiguration.cs @@ -0,0 +1,45 @@ +// using View_by_Distance.Shared.Models.Methods; + +// namespace View_by_Distance.Shared.Models.Properties; + +// public interface IConfiguration +// { + +// public bool? checkJsonForDistanceResults; +// public bool? loadOrCreateThenSaveDistanceResults; +// public bool? loadOrCreateThenSaveImageFacesResults; +// public bool? loadOrCreateThenSaveIndex; +// public bool? overrideForFaceImages; +// public bool? overrideForFaceLandmarkImages; +// public bool? overrideForResizeImages; +// public bool? propertiesChangedForDistance; +// public bool? propertiesChangedForFaces; +// public bool? propertiesChangedForIndex; +// public bool? propertiesChangedForMetadata; +// public bool? propertiesChangedForProperty; +// public bool? propertiesChangedForResize; +// public bool? reverse; +// public bool? saveFullYearOfRandomFiles; +// public bool? testDistanceResults; +// public int? distanceFactor; +// public int? locationConfidenceFactor; +// public int? mappedMaxIndex; +// public int? maxImagesInDirectoryForTopLevelFirstPass; +// public int? maxItemsInDistanceCollection; +// public int? numJitters; +// public int? outputQuality; +// public int? paddingLoops; +// public string dateGroup; +// public string modelDirectory; +// public string modelName; +// public string outputExtension; +// public string predictorModelName; +// public string rootDirectory; +// public string[] ignoreExtensions; +// public string[] ignoreRelativePaths; +// public string[] mixedYearRelativePaths; +// public string[] outputResolutions; +// public string[] saveFaceLandmarkForOutputResolutions; +// public string[] validResolutions; + +// } \ No newline at end of file diff --git a/Shared/Models/Properties/IConsole.cs b/Shared/Models/Properties/IConsole.cs new file mode 100644 index 0000000..85bcc94 --- /dev/null +++ b/Shared/Models/Properties/IConsole.cs @@ -0,0 +1,6 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IConsole +{ + +} \ No newline at end of file diff --git a/Shared/Models/Properties/IDirectoryFileSystem.cs b/Shared/Models/Properties/IDirectoryFileSystem.cs new file mode 100644 index 0000000..b2616d8 --- /dev/null +++ b/Shared/Models/Properties/IDirectoryFileSystem.cs @@ -0,0 +1,12 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IDirectoryFileSystem +{ + + // protected new string ClassName { get; } + // protected new string DataDisplayFileName { get; } + // protected new string DataFullFileName { get; } + // protected new string Display { get; } + // protected new DateTime LastModified { get; } + +} \ No newline at end of file diff --git a/Shared/Models/Properties/IFace.cs b/Shared/Models/Properties/IFace.cs new file mode 100644 index 0000000..71f8bf2 --- /dev/null +++ b/Shared/Models/Properties/IFace.cs @@ -0,0 +1,18 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IFace +{ + +#pragma warning disable IDE1006 + public double? α { get; } +#pragma warning restore IDE1006 + public DateTime DateTime { get; } + public Models.FaceEncoding FaceEncoding { get; } + public Dictionary FaceLandmarks { get; } + public Models.Location Location { get; } + public int? LocationIndex { get; } + public Models.OutputResolution OutputResolution { get; } + public bool Populated { get; } + public string RelativePath { get; } + +} \ No newline at end of file diff --git a/Shared/Models/Properties/IFaceEncoding.cs b/Shared/Models/Properties/IFaceEncoding.cs new file mode 100644 index 0000000..5cd6707 --- /dev/null +++ b/Shared/Models/Properties/IFaceEncoding.cs @@ -0,0 +1,9 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IFaceEncoding +{ + + public double[] RawEncoding { get; } + public int Size { get; } + +} \ No newline at end of file diff --git a/Shared/Models/Properties/IFaceFileSystem.cs b/Shared/Models/Properties/IFaceFileSystem.cs new file mode 100644 index 0000000..8befc0f --- /dev/null +++ b/Shared/Models/Properties/IFaceFileSystem.cs @@ -0,0 +1,30 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IFaceFileSystem // : IFaceFileSystem +{ + + // protected new string ClassName { get; } + public string Confidence { get; } + // protected new string DataDisplayFileName { get; } + // protected new string DataFullFileName { get; } + // protected new string Display { get; } + public int? FaceBottom { get; } + public string FaceFullFileName { get; } + public int? FaceHeight { get; } + public int? FaceLeft { get; } + public string FaceRelativePath { get; } + public int? FaceRight { get; } + public int? FaceTop { get; } + public int? FaceWidth { get; } + public int ImageHeight { get; } + public int ImageWidth { get; } + // protected new DateTime LastModified { get; } + public string LocationDisplayIndex { get; } + public int? LocationIndex { get; } + public bool? Populated { get; } + public string RelativePath { get; } + public string SourceFullFileName { get; } + public string SourceRelativePath { get; } + public long? SourceSize { get; } + +} \ No newline at end of file diff --git a/Shared/Models/Properties/IFacePoint.cs b/Shared/Models/Properties/IFacePoint.cs new file mode 100644 index 0000000..90039cc --- /dev/null +++ b/Shared/Models/Properties/IFacePoint.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IFacePoint +{ + + public int Index { get; } + public int X { get; } + public int Y { get; } + +} \ No newline at end of file diff --git a/Shared/Models/Properties/IFileSystem.cs b/Shared/Models/Properties/IFileSystem.cs new file mode 100644 index 0000000..25786e6 --- /dev/null +++ b/Shared/Models/Properties/IFileSystem.cs @@ -0,0 +1,12 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IFileSystem +{ + + public string ClassName { get; } + public string DataDisplayFileName { get; } + public string DataFullFileName { get; } + public string Display { get; } + public DateTime LastModified { get; } + +} \ No newline at end of file diff --git a/Shared/Models/Properties/IIdentify.cs b/Shared/Models/Properties/IIdentify.cs new file mode 100644 index 0000000..9eb6f89 --- /dev/null +++ b/Shared/Models/Properties/IIdentify.cs @@ -0,0 +1,12 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IIdentify +{ + + public int DirectoryCount { get; } + public string ParentDirectoryName { get; } + public string Person { get; } + public string PossibleYear { get; } + public string RelativePath { get; } + +} \ No newline at end of file diff --git a/Shared/Models/Properties/IIndex.cs b/Shared/Models/Properties/IIndex.cs new file mode 100644 index 0000000..8e77745 --- /dev/null +++ b/Shared/Models/Properties/IIndex.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IIndex +{ + + public DateTime? DateTime { get; } + public int? Index { get; } + public List RelativePaths { get; } + +} \ No newline at end of file diff --git a/Shared/Models/Properties/ILocation.cs b/Shared/Models/Properties/ILocation.cs new file mode 100644 index 0000000..d404ace --- /dev/null +++ b/Shared/Models/Properties/ILocation.cs @@ -0,0 +1,12 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface ILocation +{ + + public double Confidence { get; } + public int Bottom { get; } + public int Left { get; } + public int Right { get; } + public int Top { get; } + +} \ No newline at end of file diff --git a/Shared/Models/Properties/IMetadataFile.cs b/Shared/Models/Properties/IMetadataFile.cs new file mode 100644 index 0000000..9b8ae7c --- /dev/null +++ b/Shared/Models/Properties/IMetadataFile.cs @@ -0,0 +1,9 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IMetadataFile +{ + + public MetadataFileId Id { get; } //string + public MetadataFileCollection Collection { get; } //string + +} // ... \ No newline at end of file diff --git a/Shared/Models/Properties/IMetadataFileCollection.cs b/Shared/Models/Properties/IMetadataFileCollection.cs new file mode 100644 index 0000000..9c093c5 --- /dev/null +++ b/Shared/Models/Properties/IMetadataFileCollection.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IMetadataFileCollection +{ + + public Dictionary>> Values { get; } + +} // ... \ No newline at end of file diff --git a/Shared/Models/Properties/IMetadataFileId.cs b/Shared/Models/Properties/IMetadataFileId.cs new file mode 100644 index 0000000..889fded --- /dev/null +++ b/Shared/Models/Properties/IMetadataFileId.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IMetadataFileId +{ + + public string Value { get; } + +} // ... \ No newline at end of file diff --git a/Shared/Models/Properties/INavigate.cs b/Shared/Models/Properties/INavigate.cs new file mode 100644 index 0000000..27a73a3 --- /dev/null +++ b/Shared/Models/Properties/INavigate.cs @@ -0,0 +1,12 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface INavigate +{ + + public List Levels { get; } + public string SourceDirectory { get; } + public string DirectoryRelativePath { get; } + public Models.FaceFileSystem[] FaceFileSystemCollection { get; } + public Models.DirectoryFileSystem[] DirectoryFileSystemCollection { get; } + +} \ No newline at end of file diff --git a/Shared/Models/Properties/IOutputResolution.cs b/Shared/Models/Properties/IOutputResolution.cs new file mode 100644 index 0000000..ede782c --- /dev/null +++ b/Shared/Models/Properties/IOutputResolution.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IOutputResolution +{ + + public int Height { get; } + public int Orientation { get; } + public int Width { get; } + +} \ No newline at end of file diff --git a/Shared/Models/Properties/IPerson.cs b/Shared/Models/Properties/IPerson.cs new file mode 100644 index 0000000..8d5111e --- /dev/null +++ b/Shared/Models/Properties/IPerson.cs @@ -0,0 +1,15 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IPerson +{ + + public PersonId Id { get; } //long + public PersonBirthday Birthday { get; } //DateTime + public PersonName Name { get; } //JsonValueKind.Object + public List Comments { get; } //string + public List URLs { get; } //string + public List Numbers { get; } //string + public List Emails { get; } //string + public List Addresses { get; } //JsonValueKind.Array + +} // ... \ No newline at end of file diff --git a/Shared/Models/Properties/IPersonAddress.cs b/Shared/Models/Properties/IPersonAddress.cs new file mode 100644 index 0000000..c303926 --- /dev/null +++ b/Shared/Models/Properties/IPersonAddress.cs @@ -0,0 +1,11 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IPersonAddress +{ + + public PersonAddressStreet Street { get; } //string + public PersonAddressCity City { get; } //string + public PersonAddressState State { get; } //string + public PersonAddressZipCode ZipCode { get; } //string + +} // ... \ No newline at end of file diff --git a/Shared/Models/Properties/IPersonAddressCity.cs b/Shared/Models/Properties/IPersonAddressCity.cs new file mode 100644 index 0000000..9560f7c --- /dev/null +++ b/Shared/Models/Properties/IPersonAddressCity.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IPersonAddressCity +{ + + public string Value { get; } + +} // ... \ No newline at end of file diff --git a/Shared/Models/Properties/IPersonAddressState.cs b/Shared/Models/Properties/IPersonAddressState.cs new file mode 100644 index 0000000..f47f233 --- /dev/null +++ b/Shared/Models/Properties/IPersonAddressState.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IPersonAddressState +{ + + public string Value { get; } + +} // ... \ No newline at end of file diff --git a/Shared/Models/Properties/IPersonAddressStreet.cs b/Shared/Models/Properties/IPersonAddressStreet.cs new file mode 100644 index 0000000..43780ae --- /dev/null +++ b/Shared/Models/Properties/IPersonAddressStreet.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IPersonAddressStreet +{ + + public string Value { get; } + +} // ... \ No newline at end of file diff --git a/Shared/Models/Properties/IPersonAddressZipCode.cs b/Shared/Models/Properties/IPersonAddressZipCode.cs new file mode 100644 index 0000000..3b7de2b --- /dev/null +++ b/Shared/Models/Properties/IPersonAddressZipCode.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IPersonAddressZipCode +{ + + public string Value { get; } + +} // ... \ No newline at end of file diff --git a/Shared/Models/Properties/IPersonBirthday.cs b/Shared/Models/Properties/IPersonBirthday.cs new file mode 100644 index 0000000..2aef872 --- /dev/null +++ b/Shared/Models/Properties/IPersonBirthday.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IPersonBirthday +{ + + public DateTime Value { get; } + +} // ... \ No newline at end of file diff --git a/Shared/Models/Properties/IPersonComment.cs b/Shared/Models/Properties/IPersonComment.cs new file mode 100644 index 0000000..8f2d490 --- /dev/null +++ b/Shared/Models/Properties/IPersonComment.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IPersonComment +{ + + public string Value { get; } + +} // ... \ No newline at end of file diff --git a/Shared/Models/Properties/IPersonEmail.cs b/Shared/Models/Properties/IPersonEmail.cs new file mode 100644 index 0000000..9bc6729 --- /dev/null +++ b/Shared/Models/Properties/IPersonEmail.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IPersonEmail +{ + + public string Value { get; } + +} // ... \ No newline at end of file diff --git a/Shared/Models/Properties/IPersonId.cs b/Shared/Models/Properties/IPersonId.cs new file mode 100644 index 0000000..8a26cca --- /dev/null +++ b/Shared/Models/Properties/IPersonId.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IPersonId +{ + + public long Value { get; } + +} // ... \ No newline at end of file diff --git a/Shared/Models/Properties/IPersonName.cs b/Shared/Models/Properties/IPersonName.cs new file mode 100644 index 0000000..67ef7c8 --- /dev/null +++ b/Shared/Models/Properties/IPersonName.cs @@ -0,0 +1,11 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IPersonName +{ + + public PersonNameFirst First { get; } //string + public PersonNameMiddle Middle { get; } //string + public PersonNameLast Last { get; } //string + public PersonNameAlias Alias { get; } //string + +} // ... \ No newline at end of file diff --git a/Shared/Models/Properties/IPersonNameAlias.cs b/Shared/Models/Properties/IPersonNameAlias.cs new file mode 100644 index 0000000..d6674e8 --- /dev/null +++ b/Shared/Models/Properties/IPersonNameAlias.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IPersonNameAlias +{ + + public string Value { get; } + +} // ... \ No newline at end of file diff --git a/Shared/Models/Properties/IPersonNameFirst.cs b/Shared/Models/Properties/IPersonNameFirst.cs new file mode 100644 index 0000000..961c6eb --- /dev/null +++ b/Shared/Models/Properties/IPersonNameFirst.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IPersonNameFirst +{ + + public string Value { get; } + +} // ... \ No newline at end of file diff --git a/Shared/Models/Properties/IPersonNameLast.cs b/Shared/Models/Properties/IPersonNameLast.cs new file mode 100644 index 0000000..170ced9 --- /dev/null +++ b/Shared/Models/Properties/IPersonNameLast.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IPersonNameLast +{ + + public string Value { get; } + +} // ... \ No newline at end of file diff --git a/Shared/Models/Properties/IPersonNameMiddle.cs b/Shared/Models/Properties/IPersonNameMiddle.cs new file mode 100644 index 0000000..338b428 --- /dev/null +++ b/Shared/Models/Properties/IPersonNameMiddle.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IPersonNameMiddle +{ + + public string Value { get; } + +} // ... \ No newline at end of file diff --git a/Shared/Models/Properties/IPersonNumber.cs b/Shared/Models/Properties/IPersonNumber.cs new file mode 100644 index 0000000..71d90b1 --- /dev/null +++ b/Shared/Models/Properties/IPersonNumber.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IPersonNumber +{ + + public string Value { get; } + +} // ... \ No newline at end of file diff --git a/Shared/Models/Properties/IPersonURL.cs b/Shared/Models/Properties/IPersonURL.cs new file mode 100644 index 0000000..91026af --- /dev/null +++ b/Shared/Models/Properties/IPersonURL.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IPersonURL +{ + + public string Value { get; } + +} // ... \ No newline at end of file diff --git a/Shared/Models/Properties/IProperty.cs b/Shared/Models/Properties/IProperty.cs new file mode 100644 index 0000000..25bf3c1 --- /dev/null +++ b/Shared/Models/Properties/IProperty.cs @@ -0,0 +1,21 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IProperty +{ + + public DateTime CreationTime { get; } + public DateTime? DateTime { get; } + public DateTime? DateTimeDigitized { get; } + public DateTime? DateTimeOriginal { get; } + public long FileSize { get; } + public DateTime? GPSDateStamp { get; } + public int? Height { get; } + public int? Id { get; } + public int[] Indices { get; } + public DateTime LastWriteTime { get; } + public string Make { get; } + public string Model { get; } + public string Orientation { get; } + public int? Width { get; } + +} \ No newline at end of file diff --git a/Shared/Models/Properties/IRelativePaths.cs b/Shared/Models/Properties/IRelativePaths.cs new file mode 100644 index 0000000..c92df43 --- /dev/null +++ b/Shared/Models/Properties/IRelativePaths.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IRelativePaths // : IRelativePaths +{ + + public string Value { get; } + +} \ No newline at end of file diff --git a/Shared/Models/Properties/IRenamePage.cs b/Shared/Models/Properties/IRenamePage.cs new file mode 100644 index 0000000..a48dafc --- /dev/null +++ b/Shared/Models/Properties/IRenamePage.cs @@ -0,0 +1,6 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IRenamePage // : IRenamePage +{ + +} \ No newline at end of file diff --git a/Shared/Models/Properties/IStorage.cs b/Shared/Models/Properties/IStorage.cs new file mode 100644 index 0000000..218bc27 --- /dev/null +++ b/Shared/Models/Properties/IStorage.cs @@ -0,0 +1,16 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IStorage +{ + + public string DistanceResultRootDirectory { get; } + public string FaceRootDirectory { get; } + public string IndexInfoRootDirectory { get; } + public string MetadataRootDirectory { get; } + public string PeopleRootDirectory { get; } + public string ResizeRootDirectory { get; } + public string RootDirectory { get; } + public string RootResultsDirectory { get; } + public string UrlRoot { get; } + +} \ No newline at end of file diff --git a/Shared/Models/Property.cs b/Shared/Models/Property.cs new file mode 100644 index 0000000..c3bd982 --- /dev/null +++ b/Shared/Models/Property.cs @@ -0,0 +1,72 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class Property : Properties.IProperty +{ + + protected bool? _WrongYear; + protected DateTime _CreationTime; + protected DateTime _LastWriteTime; + protected DateTime? _DateTime; + protected DateTime? _DateTimeDigitized; + protected DateTime? _DateTimeOriginal; + protected long _FileSize; + protected DateTime? _GPSDateStamp; + protected int? _Id; + protected int[] _Indices; + protected int? _Height; + protected int? _Width; + protected string _Make; + protected int? _MetadataGroups; + protected string _Model; + protected string _Orientation; + protected string _UniqueImageId; + public bool? WrongYear => _WrongYear; + public DateTime CreationTime => _CreationTime; + public DateTime LastWriteTime => _LastWriteTime; + public DateTime? DateTime => _DateTime; + public DateTime? DateTimeDigitized => _DateTimeDigitized; + public DateTime? DateTimeOriginal => _DateTimeOriginal; + public long FileSize => _FileSize; + public DateTime? GPSDateStamp => _GPSDateStamp; + public int? Id => _Id; + public int[] Indices => _Indices; + public int? Height => _Height; + public int? Width => _Width; + public string Make => _Make; + public int? MetadataGroups => _MetadataGroups; + public string Model => _Model; + public string Orientation => _Orientation; + public string UniqueImageId => _UniqueImageId; + + [JsonConstructor] + public Property(bool? wrongYear, DateTime creationTime, DateTime lastWriteTime, DateTime? dateTime, DateTime? dateTimeDigitized, DateTime? dateTimeOriginal, DateTime? gpsDateStamp, long fileSize, int? id, int[] indices, int? height, int? width, string make, int? metadataGroups, string model, string orientation, string uniqueImageId) + { + _CreationTime = creationTime; + _DateTime = dateTime; + _DateTimeDigitized = dateTimeDigitized; + _DateTimeOriginal = dateTimeOriginal; + _GPSDateStamp = gpsDateStamp; + _FileSize = fileSize; + _Height = height; + _Id = id; + _Indices = indices; + _LastWriteTime = lastWriteTime; + _Make = make; + _MetadataGroups = metadataGroups; + _Model = model; + _Orientation = orientation; + _Width = width; + _WrongYear = wrongYear; + _UniqueImageId = uniqueImageId; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } // ... + +} \ No newline at end of file diff --git a/Shared/Models/RelativePaths.cs b/Shared/Models/RelativePaths.cs new file mode 100644 index 0000000..b1a3d41 --- /dev/null +++ b/Shared/Models/RelativePaths.cs @@ -0,0 +1,28 @@ +using System.Text.Json; +using System.Text.Json.Serialization; +using View_by_Distance.Shared.Models.Methods; + +namespace View_by_Distance.Shared.Models; + +public class RelativePaths : Properties.IRelativePaths, IRelativePaths +{ + + protected string _Value; + public string Value => _Value; + + [JsonConstructor] + public RelativePaths(string value) => _Value = value; + + public DirectoryInfo GetDirectoryInfo(string root) + { + DirectoryInfo result = new(string.Concat(root, Value)); + return result; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/IExif.cs b/Shared/Models/Stateless/IExif.cs new file mode 100644 index 0000000..63926ee --- /dev/null +++ b/Shared/Models/Stateless/IExif.cs @@ -0,0 +1,148 @@ +namespace View_by_Distance.Shared.Models.Stateless; + +public interface IExif +{ + + enum Tags : ushort + { + GPSVersionID = 0, + GPSLatitudeRef = 1, + GPSLatitude = 2, + GPSLongitudeRef = 3, + GPSLongitude = 4, + GPSAltitudeRef = 5, + GPSAltitude = 6, + GPSTimestamp = 7, + GPSSatellites = 8, + GPSStatus = 9, + GPSMeasureMode = 10, + GPSDOP = 11, + GPSSpeedRef = 12, + GPSSpeed = 13, + GPSTrackRef = 14, + GPSTrack = 15, + GPSImgDirectionRef = 16, + GPSImgDirection = 17, + GPSMapDatum = 18, + GPSDestLatitudeRef = 19, + GPSDestLatitude = 20, + GPSDestLongitudeRef = 21, + GPSDestLongitude = 22, + GPSDestBearingRef = 23, + GPSDestBearing = 24, + GPSDestDistanceRef = 25, + GPSDestDistance = 26, + GPSProcessingMethod = 27, + GPSAreaInformation = 28, + GPSDateStamp = 29, + GPSDifferential = 30, + GPSHPositioningError = 31, + ImageWidth = 256, + ImageLength = 257, + BitsPerSample = 258, + Compression = 259, + PhotometricInterpretation = 262, + ImageDescription = 270, + Make = 271, + Model = 272, + StripOffsets = 273, + Orientation = 274, + SamplesPerPixel = 277, + RowsPerStrip = 278, + StripByteCounts = 279, + XResolution = 282, + YResolution = 283, + PlanarConfiguration = 284, + ResolutionUnit = 296, + TransferFunction = 301, + Software = 305, + DateTime = 306, + Artist = 315, + WhitePoint = 318, + PrimaryChromaticities = 319, + JPEGInterchangeFormat = 513, + JPEGInterchangeFormatLength = 514, + YCbCrCoefficients = 529, + YCbCrSubSampling = 530, + YCbCrPositioning = 531, + ReferenceBlackWhite = 532, + Copyright = 33432, + ExposureTime = 33434, + FNumber = 33437, + ExposureProgram = 34850, + SpectralSensitivity = 34852, + ISOSpeedRatings = 34855, +#pragma warning disable CA1069 + PhotographicSensitivity = 34855, +#pragma warning restore CA1069 + OECF = 34856, + SensitivityType = 34864, + StandardOutputSensitivity = 34865, + RecommendedExposureIndex = 34866, + ISOSpeed = 34867, + ISOSpeedLatitudeyyy = 34868, + ISOSpeedLatitudezzz = 34869, + ExifVersion = 36864, + DateTimeOriginal = 36867, + DateTimeDigitized = 36868, + ComponentsConfiguration = 37121, + CompressedBitsPerPixel = 37122, + ShutterSpeedValue = 37377, + ApertureValue = 37378, + BrightnessValue = 37379, + ExposureBiasValue = 37380, + MaxApertureValue = 37381, + SubjectDistance = 37382, + MeteringMode = 37383, + LightSource = 37384, + Flash = 37385, + FocalLength = 37386, + SubjectArea = 37396, + MakerNote = 37500, + UserComment = 37510, + SubsecTime = 37520, + SubsecTimeOriginal = 37521, + SubsecTimeDigitized = 37522, + XPTitle = 40091, + XPComment = 40092, + XPAuthor = 40093, + XPKeywords = 40094, + XPSubject = 40095, + FlashpixVersion = 40960, + ColorSpace = 40961, + PixelXDimension = 40962, + PixelYDimension = 40963, + RelatedSoundFile = 40964, + FlashEnergy = 41483, + SpatialFrequencyResponse = 41484, + FocalPlaneXResolution = 41486, + FocalPlaneYResolution = 41487, + FocalPlaneResolutionUnit = 41488, + SubjectLocation = 41492, + ExposureIndex = 41493, + SensingMethod = 41495, + FileSource = 41728, + SceneType = 41729, + CFAPattern = 41730, + CustomRendered = 41985, + ExposureMode = 41986, + WhiteBalance = 41987, + DigitalZoomRatio = 41988, + FocalLengthIn35mmFilm = 41989, + SceneCaptureType = 41990, + GainControl = 41991, + Contrast = 41992, + Saturation = 41993, + Sharpness = 41994, + DeviceSettingDescription = 41995, + SubjectDistanceRange = 41996, + ImageUniqueID = 42016, + CameraOwnerName = 42032, + BodySerialNumber = 42033, + LensSpecification = 42034, + LensMake = 42035, + LensModel = 42036, + LensSerialNumber = 42037 + } + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/%ClassName%.cs .ai b/Shared/Models/Stateless/Methods/%ClassName%.cs .ai new file mode 100644 index 0000000..e69de29 diff --git a/Shared/Models/Stateless/Methods/Face.cs b/Shared/Models/Stateless/Methods/Face.cs new file mode 100644 index 0000000..caf2994 --- /dev/null +++ b/Shared/Models/Stateless/Methods/Face.cs @@ -0,0 +1,99 @@ +using System.Text.Json; + +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class Face +{ + + internal static string GetJson(string jsonFileFullName) + { + string result; + FileInfo fileInfo; + string fileSegment = "FileSegment"; + result = File.ReadAllText(jsonFileFullName); + if (result.Contains(fileSegment)) + { + fileInfo = new FileInfo(jsonFileFullName); + result = result.Replace(fileSegment, nameof(Properties.IIndex.RelativePaths)).Replace("\\\\", "/"); + File.WriteAllText(fileInfo.FullName, result); + File.SetLastWriteTime(fileInfo.FullName, fileInfo.LastWriteTime); + } + if (result.Contains("/u0")) + { + fileInfo = new FileInfo(jsonFileFullName); + result = result.Replace("/u0", "\\u0"); + File.WriteAllText(fileInfo.FullName, result); + File.SetLastWriteTime(fileInfo.FullName, fileInfo.LastWriteTime); + } + return result; + } + + private static JsonElement[] GetJsonElements(string jsonFileFullName) + { + string json = GetJson(jsonFileFullName); + JsonElement[]? jsonElements = JsonSerializer.Deserialize(json); + if (jsonElements is null) + throw new Exception(); + return jsonElements; + } + + private static List GetFaces(string jsonFileFullName, int? maximum) + { + List results = new(); + Tuple? tuple; + JsonElement[] jsonElements = GetJsonElements(jsonFileFullName); + foreach (JsonElement jsonElement in jsonElements) + { + tuple = JsonSerializer.Deserialize>(jsonElement.ToString()); + if (tuple is null || tuple.Item1 is null || string.IsNullOrEmpty(tuple.Item1.RelativePath)) + continue; + results.Add(tuple.Item1); + if (maximum.HasValue && results.Count >= maximum) + break; + } + return results; + } + + internal static Models.Face GetFace(string jsonFileFullName) + { + Models.Face? result; + List results = GetFaces(jsonFileFullName, maximum: 1); + if (!results.Any()) + throw new Exception(); + result = results[0]; + return result; + } + + internal static Models.Face[] GetFaces(string jsonFileFullName) + { + List results = GetFaces(jsonFileFullName, maximum: null); + return results.ToArray(); + } + + internal static double Getα(int x1, int x2, int y1, int y2) + { + double result; + if (y1 == y2) + result = 0; + else + { + int b; + if (x1 > x2) + b = x1 - x2; + else + b = x2 - x1; + int a; + if (y1 > y2) + a = y1 - y2; + else + a = y2 - y1; + double c = Math.Sqrt(Math.Pow(a, 2) + Math.Pow(b, 2)); + if (y1 < y2) + result = (180 / Math.PI) * Math.Asin(a / c); + else + result = (180 / Math.PI) * Math.Asin(a / c) * -1; + } + return result; + } + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/FaceFileSystem.cs b/Shared/Models/Stateless/Methods/FaceFileSystem.cs new file mode 100644 index 0000000..dc67fcb --- /dev/null +++ b/Shared/Models/Stateless/Methods/FaceFileSystem.cs @@ -0,0 +1,83 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class FaceFileSystem +{ // ... + + internal static void SearchForMissingFile(string fullFileName, FileInfo fileInfo, string dataFullFileName) + { + if (fileInfo is null || string.IsNullOrEmpty(fileInfo.FullName)) + fileInfo = new FileInfo(fullFileName); + if (Directory.Exists(fileInfo.DirectoryName)) + throw new Exception($"File [{fileInfo.Name}] <{fullFileName}> doesn't exist!"); + else + { + string? parentDirectoryName = Path.GetDirectoryName(fileInfo.DirectoryName); + if (!Directory.Exists(parentDirectoryName)) + throw new Exception($"Parent directory <{parentDirectoryName}> doesn't exist!"); + else + { + string[] files = Directory.GetFiles(parentDirectoryName, Path.GetFileName(fullFileName), SearchOption.AllDirectories); + if (!files.Any()) + throw new Exception($"File [{fileInfo.Name}] <{fullFileName}> doesn't exist (deep search)!"); + else + { + if (string.IsNullOrEmpty(dataFullFileName) && !dataFullFileName.EndsWith(".json")) + throw new Exception($"Maybe file <{Path.GetFileNameWithoutExtension(fullFileName)}> was moved to <{files[0]}>!"); + else + { + string json = File.ReadAllText(dataFullFileName); + if (!json.Contains("MesaFab")) + throw new Exception($"Maybe file <{Path.GetFileNameWithoutExtension(fullFileName)}> was moved to <{files[0]}> (unkown)!"); + else + { + json = json.Replace("MesaFab", "Mesa Fab"); + fileInfo = new FileInfo(dataFullFileName); + File.WriteAllText(fileInfo.FullName, json); + File.SetLastWriteTime(fileInfo.FullName, fileInfo.LastWriteTime); + _ = new FileInfo(fullFileName); + } + } + } + } + } + } + + internal static Models.FaceFileSystem[] GetFaceFileSystemCollection(string requestPath, (string RootResultsDirectoryAbsoluteUri, string C_ResizeContentDirectory, string D_FacesContentDirectory, string E_DistanceCollectionDirectory) tuple, string selectedFileFullName) + { + List results = new(); + FileInfo fileInfo; + int? locationIndex; + string jsonFileName; + string? directoryName; + string fileNameWithoutExtension; + Models.FaceFileSystem faceFileSystem; + string eDistanceCollectionfileFullName; + Models.Face[] face = Face.GetFaces(selectedFileFullName); + string extension = Path.GetExtension(selectedFileFullName); + for (int i = 0; i < face.Length; i++) + { + if (face[i] is null) + continue; + locationIndex = face[i].LocationIndex; + if (locationIndex is null) + locationIndex = 0; + else + locationIndex = locationIndex.Value; + directoryName = Path.GetDirectoryName(face[i].RelativePath); + if (directoryName is null) + continue; + fileNameWithoutExtension = Path.GetFileNameWithoutExtension(face[i].RelativePath); + jsonFileName = string.Concat(locationIndex.Value, " - ", fileNameWithoutExtension, extension); + eDistanceCollectionfileFullName = string.Concat(tuple.E_DistanceCollectionDirectory, Path.Combine(directoryName, fileNameWithoutExtension, jsonFileName)); + if (i == 0 && extension is ".json" && eDistanceCollectionfileFullName != selectedFileFullName) + throw new Exception(); + fileInfo = new(eDistanceCollectionfileFullName); + if (!fileInfo.Exists) + throw new Exception($"File <{eDistanceCollectionfileFullName}> doesn't exist!"); + faceFileSystem = new Models.FaceFileSystem(requestPath, tuple.RootResultsDirectoryAbsoluteUri.Length, tuple.C_ResizeContentDirectory, tuple.D_FacesContentDirectory, fileInfo.FullName, face[i]); + results.Add(faceFileSystem); + } + return results.ToArray(); + } + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/FileSystem.cs b/Shared/Models/Stateless/Methods/FileSystem.cs new file mode 100644 index 0000000..c5a2989 --- /dev/null +++ b/Shared/Models/Stateless/Methods/FileSystem.cs @@ -0,0 +1,50 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class FileSystem +{ // ... + + internal static List GetFileSystemCollection(string requestPath, (string RootResultsDirectoryAbsoluteUri, string C_ResizeContentDirectory, string D_FacesContentDirectory, string E_DistanceCollectionDirectory) tuple, string[] directories, string[] files, bool all) + { + List results = new(); + Models.Face face; + DirectoryInfo directoryInfo; + Models.FileSystem fileSystem; + Models.FaceFileSystem faceFileSystem; + IEnumerator subDirectoryFiles; + List faceFileSystemCollection = new(); + for (int i = 0; i < directories.Length; i++) + { + subDirectoryFiles = Directory.EnumerateFiles(directories[i], "*.json", SearchOption.TopDirectoryOnly).GetEnumerator(); + if (!subDirectoryFiles.MoveNext()) + { + directoryInfo = new(directories[i]); + fileSystem = new Models.DirectoryFileSystem(directoryInfo); + results.Add(fileSystem); + } + else + { + for (int j = 0; j < int.MaxValue; j++) + { + face = Face.GetFace(subDirectoryFiles.Current); + faceFileSystem = new Models.FaceFileSystem(requestPath, tuple.RootResultsDirectoryAbsoluteUri.Length, tuple.C_ResizeContentDirectory, tuple.D_FacesContentDirectory, subDirectoryFiles.Current, face); + if (!all) + results.Add(faceFileSystem); + else + faceFileSystemCollection.Add(faceFileSystem); + if (!all || !subDirectoryFiles.MoveNext()) + break; + } + } + } + for (int i = 0; i < files.Length; i++) + { + face = Face.GetFace(files[i]); + faceFileSystem = new Models.FaceFileSystem(requestPath, tuple.RootResultsDirectoryAbsoluteUri.Length, tuple.C_ResizeContentDirectory, tuple.D_FacesContentDirectory, files[i], face); + results.Add(faceFileSystem); + } + if (all) + results.AddRange(faceFileSystemCollection); + return results; + } + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/I%ClassName%.cs .ai b/Shared/Models/Stateless/Methods/I%ClassName%.cs .ai new file mode 100644 index 0000000..e69de29 diff --git a/Shared/Models/Stateless/Methods/IBackgroundPage.cs b/Shared/Models/Stateless/Methods/IBackgroundPage.cs new file mode 100644 index 0000000..02a36dd --- /dev/null +++ b/Shared/Models/Stateless/Methods/IBackgroundPage.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IBackgroundPage +{ + + void OnGet(bool? message_clear = null, bool? exceptions_clear = null, bool? set_is_primary_instance = null); + + static string GetRouteName() => nameof(IBackgroundPage).Replace("Page", string.Empty)[1..]; + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IDirectoryFileSystem.cs b/Shared/Models/Stateless/Methods/IDirectoryFileSystem.cs new file mode 100644 index 0000000..e7e1a4c --- /dev/null +++ b/Shared/Models/Stateless/Methods/IDirectoryFileSystem.cs @@ -0,0 +1,6 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IDirectoryFileSystem +{ + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IFace.cs b/Shared/Models/Stateless/Methods/IFace.cs new file mode 100644 index 0000000..3ae7b75 --- /dev/null +++ b/Shared/Models/Stateless/Methods/IFace.cs @@ -0,0 +1,16 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IFace +{ // ... + + double TestStatic_Getα(int x1, int x2, int y1, int y2); + string TestStatic_GetJson(string jsonFileFullName); + Models.Face TestStatic_GetFace(string jsonFileFullName); + Models.Face[] TestStatic_GetFaces(string jsonFileFullName); + + static double Getα(int x1, int x2, int y1, int y2) => Face.Getα(x1, x2, y1, y2); + static string GetJson(string jsonFileFullName) => Face.GetJson(jsonFileFullName); + static Models.Face GetFace(string jsonFileFullName) => Face.GetFace(jsonFileFullName); + static Models.Face[] GetFaces(string jsonFileFullName) => Face.GetFaces(jsonFileFullName); + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IFaceFileSystem.cs b/Shared/Models/Stateless/Methods/IFaceFileSystem.cs new file mode 100644 index 0000000..2af43dc --- /dev/null +++ b/Shared/Models/Stateless/Methods/IFaceFileSystem.cs @@ -0,0 +1,12 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IFaceFileSystem : IFileSystem +{ // ... + + void TestStatic_SearchForMissingFile(string fullFileName, FileInfo fileInfo, string dataFullFileName); + Models.FaceFileSystem[][] TestStatic_GetFaceFileSystemCollection(string requestPath, string rootResultsDirectory, (string RootResultsDirectoryAbsoluteUri, string C_ResizeContentDirectory, string D_FacesContentDirectory, string E_DistanceCollectionDirectory) tuple, string selectedFileFullName); + + static void SearchForMissingFile(string fullFileName, FileInfo fileInfo, string dataFullFileName) => FaceFileSystem.SearchForMissingFile(fullFileName, fileInfo, dataFullFileName); + static Models.FaceFileSystem[] GetFaceFileSystemCollection(string requestPath, (string RootResultsDirectoryAbsoluteUri, string C_ResizeContentDirectory, string D_FacesContentDirectory, string E_DistanceCollectionDirectory) tuple, string selectedFileFullName) => FaceFileSystem.GetFaceFileSystemCollection(requestPath, tuple, selectedFileFullName); + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IFileSystem.cs b/Shared/Models/Stateless/Methods/IFileSystem.cs new file mode 100644 index 0000000..f1ff3b2 --- /dev/null +++ b/Shared/Models/Stateless/Methods/IFileSystem.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IFileSystem +{ // ... + + List TestStatic_GetFileSystemCollection(string requestPath, string rootResultsDirectory, (string RootResultsDirectoryAbsoluteUri, string C_ResizeContentDirectory, string D_FacesContentDirectory, string E_DistanceCollectionDirectory) tuple, string[] directories, string[] files, bool all); + + static List GetFileSystemCollection(string requestPath, (string RootResultsDirectoryAbsoluteUri, string C_ResizeContentDirectory, string D_FacesContentDirectory, string E_DistanceCollectionDirectory) tuple, string[] directories, string[] files, bool all) => FileSystem.GetFileSystemCollection(requestPath, tuple, directories, files, all); + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IIndex.cs b/Shared/Models/Stateless/Methods/IIndex.cs new file mode 100644 index 0000000..9563570 --- /dev/null +++ b/Shared/Models/Stateless/Methods/IIndex.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IIndex +{ // ... + + string TestStatic_GetJson(string jsonFileFullName, FileInfo fileInfo); + + static string GetJson(string jsonFileFullName, FileInfo fileInfo) => Index.GetJson(jsonFileFullName, fileInfo); + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IMetadataFile.cs b/Shared/Models/Stateless/Methods/IMetadataFile.cs new file mode 100644 index 0000000..6ff89c3 --- /dev/null +++ b/Shared/Models/Stateless/Methods/IMetadataFile.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IMetadataFile +{ + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IMetadataFileCollection.cs b/Shared/Models/Stateless/Methods/IMetadataFileCollection.cs new file mode 100644 index 0000000..5efd231 --- /dev/null +++ b/Shared/Models/Stateless/Methods/IMetadataFileCollection.cs @@ -0,0 +1,12 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IMetadataFileCollection +{ + + Dictionary>> TestStatic_GetDefaultValue() => MetadataFileCollection.GetDefaultValue(); // {{1}}SingletonValue + + static Dictionary>> GetDefaultValue() => MetadataFileCollection.GetDefaultValue(); // {{1}}SingletonValue + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IMetadataFileId.cs b/Shared/Models/Stateless/Methods/IMetadataFileId.cs new file mode 100644 index 0000000..3b8de11 --- /dev/null +++ b/Shared/Models/Stateless/Methods/IMetadataFileId.cs @@ -0,0 +1,12 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IMetadataFileId +{ + + string TestStatic_GetDefaultValue() => MetadataFileId.GetDefaultValue(); // {{1}}SingletonValue + + static string GetDefaultValue() => MetadataFileId.GetDefaultValue(); // {{1}}SingletonValue + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IMethodName.cs b/Shared/Models/Stateless/Methods/IMethodName.cs new file mode 100644 index 0000000..f3c9ea5 --- /dev/null +++ b/Shared/Models/Stateless/Methods/IMethodName.cs @@ -0,0 +1,10 @@ +using System.Runtime.CompilerServices; + +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IMethodName +{ + + static string? GetActualAsyncMethodName([CallerMemberName] string? name = null) => name; + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IPerson.cs b/Shared/Models/Stateless/Methods/IPerson.cs new file mode 100644 index 0000000..d837cce --- /dev/null +++ b/Shared/Models/Stateless/Methods/IPerson.cs @@ -0,0 +1,23 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IPerson +{ + + // ... + + Dictionary TestStatic_Split(string knownPeopleFile); + static Dictionary Split(string knownPeopleFile) => Person.Split(knownPeopleFile); + + Models.Person[] TestStatic_GetPeople(Models.Properties.IStorage storage); + static Models.Person[] GetPeople(Models.Properties.IStorage storage) => Person.GetPeople(storage); + + void TestStatic_SavePerson(Models.Properties.IStorage storage, Models.Person person); + static void SavePerson(Models.Properties.IStorage storage, Models.Person person) => Person.SavePerson(storage, person); + + string TestStatic_GetFileFullName(Models.Properties.IStorage storage, Models.Person person); + static string GetFileFullName(Models.Properties.IStorage storage, Models.Person person) => PersonBirthday.GetFileFullName(storage, person.Birthday); + + Models.Person TestStatic_CreatePerson(Models.Properties.IStorage storage, Models.PersonBirthday birthday, Models.PersonName name, List comments, List urls, List numbers, List emails, List addresses); + static Models.Person CreatePerson(Models.Properties.IStorage storage, Models.PersonBirthday birthday, Models.PersonName name, List comments, List urls, List numbers, List emails, List addresses) => Person.CreatePerson(storage, birthday, name, comments, urls, numbers, emails, addresses); + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IPersonAddress.cs b/Shared/Models/Stateless/Methods/IPersonAddress.cs new file mode 100644 index 0000000..b213f56 --- /dev/null +++ b/Shared/Models/Stateless/Methods/IPersonAddress.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IPersonAddress +{ + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IPersonAddressCity.cs b/Shared/Models/Stateless/Methods/IPersonAddressCity.cs new file mode 100644 index 0000000..be77078 --- /dev/null +++ b/Shared/Models/Stateless/Methods/IPersonAddressCity.cs @@ -0,0 +1,12 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IPersonAddressCity +{ + + string TestStatic_GetDefaultValue() => PersonAddressCity.GetDefaultValue(); // {{1}}SingletonValue + + static string GetDefaultValue() => PersonAddressCity.GetDefaultValue(); // {{1}}SingletonValue + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IPersonAddressState.cs b/Shared/Models/Stateless/Methods/IPersonAddressState.cs new file mode 100644 index 0000000..e6f0628 --- /dev/null +++ b/Shared/Models/Stateless/Methods/IPersonAddressState.cs @@ -0,0 +1,12 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IPersonAddressState +{ + + string TestStatic_GetDefaultValue() => PersonAddressState.GetDefaultValue(); // {{1}}SingletonValue + + static string GetDefaultValue() => PersonAddressState.GetDefaultValue(); // {{1}}SingletonValue + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IPersonAddressStreet.cs b/Shared/Models/Stateless/Methods/IPersonAddressStreet.cs new file mode 100644 index 0000000..666ba58 --- /dev/null +++ b/Shared/Models/Stateless/Methods/IPersonAddressStreet.cs @@ -0,0 +1,12 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IPersonAddressStreet +{ + + string TestStatic_GetDefaultValue() => PersonAddressStreet.GetDefaultValue(); // {{1}}SingletonValue + + static string GetDefaultValue() => PersonAddressStreet.GetDefaultValue(); // {{1}}SingletonValue + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IPersonAddressZipCode.cs b/Shared/Models/Stateless/Methods/IPersonAddressZipCode.cs new file mode 100644 index 0000000..2538ed7 --- /dev/null +++ b/Shared/Models/Stateless/Methods/IPersonAddressZipCode.cs @@ -0,0 +1,12 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IPersonAddressZipCode +{ + + string TestStatic_GetDefaultValue() => PersonAddressZipCode.GetDefaultValue(); // {{1}}SingletonValue + + static string GetDefaultValue() => PersonAddressZipCode.GetDefaultValue(); // {{1}}SingletonValue + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IPersonBirthday.cs b/Shared/Models/Stateless/Methods/IPersonBirthday.cs new file mode 100644 index 0000000..0862cb3 --- /dev/null +++ b/Shared/Models/Stateless/Methods/IPersonBirthday.cs @@ -0,0 +1,30 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IPersonBirthday +{ + + DateTime TestStatic_GetDefaultValue() => PersonBirthday.GetDefaultValue(); // {{1}}SingletonValue + + static DateTime GetDefaultValue() => PersonBirthday.GetDefaultValue(); // {{1}}SingletonValue + + // ... + + string TestStatic_GetFormat() => PersonBirthday.GetFormat(); + static string GetFormat() => PersonBirthday.GetFormat(); + + Models.PersonBirthday TestStatic_GetNextBirthdate(Models.Properties.IStorage storage) => PersonBirthday.GetNextBirthdate(storage); + static Models.PersonBirthday GetNextBirthdate(Models.Properties.IStorage storage) => PersonBirthday.GetNextBirthdate(storage); + + string TestStatic_GetFormated(Models.PersonBirthday personBirthday) => PersonBirthday.GetFormated(personBirthday); + static string GetFormated(Models.PersonBirthday personBirthday) => PersonBirthday.GetFormated(personBirthday); + + string TestStatic_GetFileName(Models.PersonBirthday personBirthday) => PersonBirthday.GetFileName(personBirthday); + static string GetFileName(Models.PersonBirthday personBirthday) => PersonBirthday.GetFileName(personBirthday); + + bool TestStatic_DoesBirthDateExits(Models.Properties.IStorage storage, Models.PersonBirthday personBirthday) => DoesBirthDateExits(storage, personBirthday); + static bool DoesBirthDateExits(Models.Properties.IStorage storage, Models.PersonBirthday personBirthday) => DoesBirthDateExits(storage, personBirthday); + + string TestStatic_GetFileFullName(Models.Properties.IStorage storage, Models.PersonBirthday personBirthday) => PersonBirthday.GetFileFullName(storage, personBirthday); + static string GetFileFullName(Models.Properties.IStorage storage, Models.PersonBirthday personBirthday) => PersonBirthday.GetFileFullName(storage, personBirthday); + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IPersonComment.cs b/Shared/Models/Stateless/Methods/IPersonComment.cs new file mode 100644 index 0000000..fa4f7dd --- /dev/null +++ b/Shared/Models/Stateless/Methods/IPersonComment.cs @@ -0,0 +1,12 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IPersonComment +{ + + string TestStatic_GetDefaultValue() => PersonComment.GetDefaultValue(); // <{1}>PluralValue + + static string GetDefaultValue() => PersonComment.GetDefaultValue(); // <{1}>PluralValue + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IPersonEmail.cs b/Shared/Models/Stateless/Methods/IPersonEmail.cs new file mode 100644 index 0000000..2afd35e --- /dev/null +++ b/Shared/Models/Stateless/Methods/IPersonEmail.cs @@ -0,0 +1,12 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IPersonEmail +{ + + string TestStatic_GetDefaultValue() => PersonEmail.GetDefaultValue(); // <{1}>PluralValue + + static string GetDefaultValue() => PersonEmail.GetDefaultValue(); // <{1}>PluralValue + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IPersonId.cs b/Shared/Models/Stateless/Methods/IPersonId.cs new file mode 100644 index 0000000..cd66a76 --- /dev/null +++ b/Shared/Models/Stateless/Methods/IPersonId.cs @@ -0,0 +1,12 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IPersonId +{ + + long TestStatic_GetDefaultValue() => PersonId.GetDefaultValue(); // {{1}}SingletonValue + + static long GetDefaultValue() => PersonId.GetDefaultValue(); // {{1}}SingletonValue + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IPersonName.cs b/Shared/Models/Stateless/Methods/IPersonName.cs new file mode 100644 index 0000000..a238d1b --- /dev/null +++ b/Shared/Models/Stateless/Methods/IPersonName.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IPersonName +{ + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IPersonNameAlias.cs b/Shared/Models/Stateless/Methods/IPersonNameAlias.cs new file mode 100644 index 0000000..ecf2860 --- /dev/null +++ b/Shared/Models/Stateless/Methods/IPersonNameAlias.cs @@ -0,0 +1,12 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IPersonNameAlias +{ + + string TestStatic_GetDefaultValue() => PersonNameAlias.GetDefaultValue(); // {{1}}SingletonValue + + static string GetDefaultValue() => PersonNameAlias.GetDefaultValue(); // {{1}}SingletonValue + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IPersonNameFirst.cs b/Shared/Models/Stateless/Methods/IPersonNameFirst.cs new file mode 100644 index 0000000..57e4270 --- /dev/null +++ b/Shared/Models/Stateless/Methods/IPersonNameFirst.cs @@ -0,0 +1,12 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IPersonNameFirst +{ + + string TestStatic_GetDefaultValue() => PersonNameFirst.GetDefaultValue(); // {{1}}SingletonValue + + static string GetDefaultValue() => PersonNameFirst.GetDefaultValue(); // {{1}}SingletonValue + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IPersonNameLast.cs b/Shared/Models/Stateless/Methods/IPersonNameLast.cs new file mode 100644 index 0000000..e5b9c8e --- /dev/null +++ b/Shared/Models/Stateless/Methods/IPersonNameLast.cs @@ -0,0 +1,12 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IPersonNameLast +{ + + string TestStatic_GetDefaultValue() => PersonNameLast.GetDefaultValue(); // {{1}}SingletonValue + + static string GetDefaultValue() => PersonNameLast.GetDefaultValue(); // {{1}}SingletonValue + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IPersonNameMiddle.cs b/Shared/Models/Stateless/Methods/IPersonNameMiddle.cs new file mode 100644 index 0000000..c7a82f2 --- /dev/null +++ b/Shared/Models/Stateless/Methods/IPersonNameMiddle.cs @@ -0,0 +1,12 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IPersonNameMiddle +{ + + string TestStatic_GetDefaultValue() => PersonNameMiddle.GetDefaultValue(); // {{1}}SingletonValue + + static string GetDefaultValue() => PersonNameMiddle.GetDefaultValue(); // {{1}}SingletonValue + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IPersonNumber.cs b/Shared/Models/Stateless/Methods/IPersonNumber.cs new file mode 100644 index 0000000..da7d722 --- /dev/null +++ b/Shared/Models/Stateless/Methods/IPersonNumber.cs @@ -0,0 +1,12 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IPersonNumber +{ + + string TestStatic_GetDefaultValue() => PersonNumber.GetDefaultValue(); // <{1}>PluralValue + + static string GetDefaultValue() => PersonNumber.GetDefaultValue(); // <{1}>PluralValue + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IPersonURL.cs b/Shared/Models/Stateless/Methods/IPersonURL.cs new file mode 100644 index 0000000..ebd5355 --- /dev/null +++ b/Shared/Models/Stateless/Methods/IPersonURL.cs @@ -0,0 +1,12 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IPersonURL +{ + + string TestStatic_GetDefaultValue() => PersonURL.GetDefaultValue(); // <{1}>PluralValue + + static string GetDefaultValue() => PersonURL.GetDefaultValue(); // <{1}>PluralValue + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IStorage.cs b/Shared/Models/Stateless/Methods/IStorage.cs new file mode 100644 index 0000000..0f38465 --- /dev/null +++ b/Shared/Models/Stateless/Methods/IStorage.cs @@ -0,0 +1,14 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IStorage +{ + + // ... + + bool TestStatic_WriteAllText(string path, string contents, bool compareBeforeWrite); + static bool WriteAllText(string path, string contents, bool compareBeforeWrite) => Storage.WriteAllText(path, contents, compareBeforeWrite); + + (string RootResultsDirectoryAbsoluteUri, string C_ResizeContentDirectory, string D_FacesContentDirectory, string E_DistanceCollectionDirectory) TestStatic_GetTuple(Models.Properties.IStorage storage); + static (string RootResultsDirectoryAbsoluteUri, string C_ResizeContentDirectory, string D_FacesContentDirectory, string E_DistanceCollectionDirectory) GetTuple(Models.Properties.IStorage storage) => new(new Uri(storage.RootResultsDirectory).AbsoluteUri, Path.Combine(storage.ResizeRootDirectory, "()"), Path.Combine(storage.FaceRootDirectory, "()"), Path.Combine(storage.DistanceResultRootDirectory, "[]")); + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IWorkingDirectory.cs b/Shared/Models/Stateless/Methods/IWorkingDirectory.cs new file mode 100644 index 0000000..4adc338 --- /dev/null +++ b/Shared/Models/Stateless/Methods/IWorkingDirectory.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IWorkingDirectory +{ + + static string GetWorkingDirectory(string? executingAssemblyName, string subDirectoryName) => WorkingDirectory.GetWorkingDirectory(executingAssemblyName, subDirectoryName); + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/ImageHelper.cs b/Shared/Models/Stateless/Methods/ImageHelper.cs new file mode 100644 index 0000000..cb1033b --- /dev/null +++ b/Shared/Models/Stateless/Methods/ImageHelper.cs @@ -0,0 +1,130 @@ +using System.Drawing; + +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class ImageHelper +{ + + private static bool StartsWith(byte[] thisBytes, byte[] thatBytes) + { + for (int i = 0; i < thatBytes.Length; i += 1) + { + if (thisBytes[i] != thatBytes[i]) + return false; + } + return true; + } + + private static short ReadLittleEndianInt16(BinaryReader binaryReader) + { + byte[] bytes = new byte[sizeof(short)]; + for (int i = 0; i < sizeof(short); i += 1) + bytes[sizeof(short) - 1 - i] = binaryReader.ReadByte(); + return BitConverter.ToInt16(bytes, 0); + } + + private static int ReadLittleEndianInt32(BinaryReader binaryReader) + { + byte[] bytes = new byte[sizeof(int)]; + for (int i = 0; i < sizeof(int); i += 1) + bytes[sizeof(int) - 1 - i] = binaryReader.ReadByte(); + return BitConverter.ToInt32(bytes, 0); + } + + private static Size DecodeBitmap(BinaryReader binaryReader) + { + _ = binaryReader.ReadBytes(16); + int width = binaryReader.ReadInt32(); + int height = binaryReader.ReadInt32(); + return new Size(width, height); + } + + private static Size DecodeGif(BinaryReader binaryReader) + { + int width = binaryReader.ReadInt16(); + int height = binaryReader.ReadInt16(); + return new Size(width, height); + } + + private static Size DecodePng(BinaryReader binaryReader) + { + _ = binaryReader.ReadBytes(8); + int width = ReadLittleEndianInt32(binaryReader); + int height = ReadLittleEndianInt32(binaryReader); + return new Size(width, height); + } + + private static Size DecodeJfif(BinaryReader binaryReader) + { + while (binaryReader.ReadByte() == 0xff) + { + byte marker = binaryReader.ReadByte(); + short chunkLength = ReadLittleEndianInt16(binaryReader); + if (marker == 0xc0) + { + _ = binaryReader.ReadByte(); + int height = ReadLittleEndianInt16(binaryReader); + int width = ReadLittleEndianInt16(binaryReader); + return new Size(width, height); + } + _ = binaryReader.ReadBytes(chunkLength - 2); + } + throw new ArgumentException("Could not recognize image format."); + } + + /// + /// Gets the dimensions of an image. + /// + /// The path of the image to get the dimensions of. + /// The dimensions of the specified image. + /// The image was of an unrecognized format. + public static Size GetDimensions(BinaryReader binaryReader, int? faceRight, int? faceBottom) + { + Size? result = null; + Dictionary> _ImageFormatDecoders = new() + { + { new byte[] { 0x42, 0x4D }, DecodeBitmap }, + { new byte[] { 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 }, DecodeGif }, + { new byte[] { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 }, DecodeGif }, + { new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }, DecodePng }, + { new byte[] { 0xff, 0xd8 }, DecodeJfif }, + }; + int maxMagicBytesLength = _ImageFormatDecoders.Keys.OrderByDescending(x => x.Length).First().Length; + byte[] magicBytes = new byte[maxMagicBytesLength]; + for (int i = 0; i < maxMagicBytesLength; i += 1) + { + magicBytes[i] = binaryReader.ReadByte(); + foreach (KeyValuePair> kvPair in _ImageFormatDecoders) + { + if (!StartsWith(magicBytes, kvPair.Key)) + continue; + result = kvPair.Value(binaryReader); + break; + } + if (result is not null) + break; + } + if (result is null) + { + if (faceRight is null || faceBottom is null) + throw new Exception("face is null!"); + result = new(faceRight.Value, faceBottom.Value); + } + return result.Value; + } + + /// + /// Gets the dimensions of an image. + /// + /// The path of the image to get the dimensions of. + /// The dimensions of the specified image. + /// The image was of an unrecognized format. + public static Size GetDimensions(string path, int? faceRight, int? faceBottom) + { + Size result; + using BinaryReader binaryReader = new(File.OpenRead(path)); + result = GetDimensions(binaryReader, faceRight, faceBottom); + return result; + } + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/Index.cs b/Shared/Models/Stateless/Methods/Index.cs new file mode 100644 index 0000000..88a44de --- /dev/null +++ b/Shared/Models/Stateless/Methods/Index.cs @@ -0,0 +1,31 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class Index +{ + + internal static string GetJson(string jsonFileFullName, FileInfo fileInfo) + { + string result; + string fileSegment = "FileSegment"; + string fileSegmentCollection = "FileSegmentCollection"; + result = File.ReadAllText(jsonFileFullName).Replace("Goolgle", "Google"); + if (result.Contains(fileSegment) || result.Contains(fileSegmentCollection)) + { + if (fileInfo is null) + fileInfo = new FileInfo(jsonFileFullName); + result = result.Replace(fileSegmentCollection, nameof(Properties.IIndex.RelativePaths)).Replace("\\\\", "/"); + File.WriteAllText(fileInfo.FullName, result); + File.SetLastWriteTime(fileInfo.FullName, fileInfo.LastWriteTime); + } + if (result.Contains("/u0")) + { + if (fileInfo is null) + fileInfo = new FileInfo(jsonFileFullName); + result = result.Replace("/u0", "\\u0"); + File.WriteAllText(fileInfo.FullName, result); + File.SetLastWriteTime(fileInfo.FullName, fileInfo.LastWriteTime); + } + return result; + } + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/MetadataFile.cs b/Shared/Models/Stateless/Methods/MetadataFile.cs new file mode 100644 index 0000000..926fe03 --- /dev/null +++ b/Shared/Models/Stateless/Methods/MetadataFile.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class MetadataFile +{ + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/MetadataFileCollection.cs b/Shared/Models/Stateless/Methods/MetadataFileCollection.cs new file mode 100644 index 0000000..1307bb2 --- /dev/null +++ b/Shared/Models/Stateless/Methods/MetadataFileCollection.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class MetadataFileCollection +{ + + internal static Dictionary>> GetDefaultValue() => new(); // {{1}}SingletonValue + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/MetadataFileId.cs b/Shared/Models/Stateless/Methods/MetadataFileId.cs new file mode 100644 index 0000000..1bc223b --- /dev/null +++ b/Shared/Models/Stateless/Methods/MetadataFileId.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class MetadataFileId +{ + + internal static string GetDefaultValue() => string.Empty; // {{1}}SingletonValue + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/Person.cs b/Shared/Models/Stateless/Methods/Person.cs new file mode 100644 index 0000000..520be2b --- /dev/null +++ b/Shared/Models/Stateless/Methods/Person.cs @@ -0,0 +1,229 @@ +using System.Text.Json; + +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class Person +{ + + // ... + + private static List ValidatePerson(Models.Properties.IStorage storage, Models.PersonId id, Models.PersonBirthday birthday, Models.PersonName name) + { + List results = new(); + if (birthday is null) + throw new Exception("Birthday must be supplied!"); + if (birthday.Value > DateTime.Now) + results.Add("Birthday must be in the past!"); + if (id is null) + throw new Exception("Birthday must be supplied!"); + if (id.Value != birthday.Value.Ticks) + results.Add("Id must be Birthday ticks!"); + if (name.First is null || string.IsNullOrEmpty(name.First.Value)) + results.Add("Fist Name must be supplied!"); + if (PersonBirthday.DoesBirthDateExits(storage, birthday)) + results.Add("Birthdate already exits!"); + return results; + } + + internal static Models.Person CreatePerson(Models.Properties.IStorage storage, Models.PersonBirthday birthday, Models.PersonName name, List comments, List urls, List numbers, List emails, List addresses) + { + Models.Person result; + Models.PersonId id = new(birthday.Value.Ticks); + if (birthday.Value == DateTime.MinValue) + birthday = PersonBirthday.GetNextBirthdate(storage); + List results = ValidatePerson(storage, id, birthday, name); + if (results.Any()) + throw new Exception(string.Join(Environment.NewLine, results)); + if (comments is null) + comments = new(); + if (urls is null) + urls = new(); + if (numbers is null) + numbers = new(); + if (emails is null) + emails = new(); + if (addresses is null) + addresses = new(); + result = new(id, birthday, name, comments, urls, numbers, emails, addresses); + return result; + } + + internal static Dictionary Split(string knownPeopleFile) + { + Dictionary results = new(); + string[] segments; + DateTime personKey; + List temporarySegments; + const string KeyFormat = "yyyy-MM-dd_HH"; + DateTime incrementDate = new(1500, 1, 1); + string[] lines = File.ReadAllLines(knownPeopleFile); + _ = incrementDate.AddDays(lines.Length); + System.Globalization.CultureInfo cultureInfo = System.Globalization.CultureInfo.InvariantCulture; + foreach (string line in lines) + { + if (string.IsNullOrEmpty(line)) + continue; + segments = line.Replace(" //", "\t//").Split('\t'); + if (segments.Length < 1) + continue; + if (segments[0].Length != KeyFormat.Length || !segments[0].Contains('-') || !segments[0].Contains('_')) + { + temporarySegments = segments.ToList(); + temporarySegments.Insert(0, incrementDate.ToString(KeyFormat)); + segments = temporarySegments.ToArray(); + incrementDate = incrementDate.AddDays(1); + } + personKey = DateTime.ParseExact(segments[0], KeyFormat, cultureInfo); + if (results.ContainsKey(personKey)) + continue; + results.Add(personKey, segments); + } + int countBefore = results.Count; + DateTime minimumDateTime = results.Keys.Min(); + for (int i = 1; i < (1000 - countBefore); i++) + { + personKey = minimumDateTime.AddDays(i * -1); + results.Add(personKey, new string[] { personKey.ToString(KeyFormat) }); + } + return results.OrderBy(l => l.Key).ToDictionary(l => l.Key, l => l.Value); + } + + internal static Dictionary GetPersonCollection(string knownPeopleFile) + { + Dictionary results = new(); + string name; + DateTime key; + string comment; + string oldName; + string mergeName; + PersonImport person; + Dictionary splitLines = Split(knownPeopleFile); + foreach (KeyValuePair splitLine in splitLines) + { + name = string.Empty; + key = splitLine.Key; + comment = string.Empty; + oldName = string.Empty; + mergeName = string.Empty; + if (splitLine.Value.Length > 1) + { + foreach (string segment in splitLine.Value) + { + if (!segment.Contains('*')) + continue; + mergeName = segment.Split('*')[1].Split('\t')[0]; + } + if (splitLine.Value[1].StartsWith("//")) + comment = splitLine.Value[1]; + else + name = splitLine.Value[1].Split('\t')[0]; + if (splitLine.Value.Length > 2) + comment = splitLine.Value[2]; + } + person = new(key, name, mergeName, oldName, comment); + results.Add(splitLine.Key, person); + } + return results; + } + + internal static void SavePerson(Models.Properties.IStorage storage, Models.Person person) + { + string fileName = IPerson.GetFileFullName(storage, person); + string json = JsonSerializer.Serialize(person, new JsonSerializerOptions { WriteIndented = true }); + _ = IStorage.WriteAllText(fileName, json, compareBeforeWrite: true); + } + + private static List GetPeopleFromText(Models.Properties.IStorage storage, string localKnownPeopleFile) + { + List results = new(); + string comment; + Models.Person person; + Models.PersonName name; + List urls; + Models.PersonBirthday birthday; + List emails = new(); + List numbers = new(); + List comments = new(); + List addresses = new(); + Dictionary keyValuePairs = GetPersonCollection(localKnownPeopleFile); + foreach (KeyValuePair keyValuePair in keyValuePairs) + { + if (string.IsNullOrEmpty(keyValuePair.Value.Name)) + continue; + urls = new(); + birthday = new(keyValuePair.Key); + name = PersonName.Create(keyValuePair.Value.Name); + if (name.First is null || string.IsNullOrEmpty(name.First.Value)) + continue; + if (!string.IsNullOrEmpty(keyValuePair.Value.Comment)) + { + comment = keyValuePair.Value.Comment[2..]; + if (!string.IsNullOrEmpty(comment)) + { + if (comment.StartsWith("http://") || comment.StartsWith("https://")) + urls.Add(new(new(comment))); + else + comments.Add(new(new(comment))); + } + } + if (!string.IsNullOrEmpty(keyValuePair.Value.OldName)) + comments.Add(new(new(keyValuePair.Value.OldName))); + person = IPerson.CreatePerson(storage, birthday, name, comments, urls, numbers, emails, addresses); + SavePerson(storage, person); + results.Add(person); + } + return results; + } + + internal static Models.Person[] GetPeople(Models.Properties.IStorage storage) + { + List results = new(); + string json; + string[] files; + FileInfo fileInfo; + Models.Person? person; + string localKnownPeopleFile; + DateTime dateTime = DateTime.MinValue; + string directory = Path.Combine(storage.PeopleRootDirectory, "{}"); + if (!Directory.Exists(directory)) + _ = Directory.CreateDirectory(directory); + if (!Directory.Exists(storage.RootDirectory)) + localKnownPeopleFile = string.Empty; + else + { + files = Directory.GetFiles(storage.RootDirectory, "*People*.txt", SearchOption.TopDirectoryOnly); + if (files.Any()) + localKnownPeopleFile = files[0]; + else + localKnownPeopleFile = string.Empty; + } + files = Directory.GetFiles(directory, "*.json", SearchOption.TopDirectoryOnly); + if (!files.Any() && string.IsNullOrEmpty(localKnownPeopleFile)) + throw new Exception("Copy \"KnownPeople.txt\" file from server!"); + foreach (string file in files) + { + fileInfo = new(file); + if (dateTime < fileInfo.LastWriteTime) + dateTime = fileInfo.LastWriteTime; + json = File.ReadAllText(file); + person = JsonSerializer.Deserialize(json); + if (person is null) + continue; + results.Add(person); + } + if (!results.Any()) + results = GetPeopleFromText(storage, localKnownPeopleFile); + else if (!string.IsNullOrEmpty(localKnownPeopleFile)) + { + fileInfo = new FileInfo(localKnownPeopleFile); + if (fileInfo.LastWriteTime > dateTime) + { + foreach (string file in files) + File.Delete(file); + results = GetPeopleFromText(storage, localKnownPeopleFile); + } + } + return results.ToArray(); + } + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/PersonAddress.cs b/Shared/Models/Stateless/Methods/PersonAddress.cs new file mode 100644 index 0000000..4837701 --- /dev/null +++ b/Shared/Models/Stateless/Methods/PersonAddress.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class PersonAddress +{ + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/PersonAddressCity.cs b/Shared/Models/Stateless/Methods/PersonAddressCity.cs new file mode 100644 index 0000000..6e54fdb --- /dev/null +++ b/Shared/Models/Stateless/Methods/PersonAddressCity.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class PersonAddressCity +{ + + internal static string GetDefaultValue() => string.Empty; // {{1}}SingletonValue + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/PersonAddressState.cs b/Shared/Models/Stateless/Methods/PersonAddressState.cs new file mode 100644 index 0000000..c4748cc --- /dev/null +++ b/Shared/Models/Stateless/Methods/PersonAddressState.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class PersonAddressState +{ + + internal static string GetDefaultValue() => string.Empty; // {{1}}SingletonValue + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/PersonAddressStreet.cs b/Shared/Models/Stateless/Methods/PersonAddressStreet.cs new file mode 100644 index 0000000..d0aea22 --- /dev/null +++ b/Shared/Models/Stateless/Methods/PersonAddressStreet.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class PersonAddressStreet +{ + + internal static string GetDefaultValue() => string.Empty; // {{1}}SingletonValue + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/PersonAddressZipCode.cs b/Shared/Models/Stateless/Methods/PersonAddressZipCode.cs new file mode 100644 index 0000000..e61d34d --- /dev/null +++ b/Shared/Models/Stateless/Methods/PersonAddressZipCode.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class PersonAddressZipCode +{ + + internal static string GetDefaultValue() => string.Empty; // {{1}}SingletonValue + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/PersonBirthday.cs b/Shared/Models/Stateless/Methods/PersonBirthday.cs new file mode 100644 index 0000000..3cd1506 --- /dev/null +++ b/Shared/Models/Stateless/Methods/PersonBirthday.cs @@ -0,0 +1,16 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class PersonBirthday +{ + + internal static DateTime GetDefaultValue() => DateTime.MinValue; // {{1}}SingletonValue + + // ... + + internal static string GetFormat() => "yyyy-MM-dd_HH"; + internal static Models.PersonBirthday GetNextBirthdate(Models.Properties.IStorage storage) => throw new Exception(storage.ToString()); // Person.GetNextBirthdate(storage); + internal static string GetFormated(Models.PersonBirthday personBirthday) => personBirthday.Value.ToString(GetFormat()); + internal static string GetFileName(Models.PersonBirthday personBirthday) => $"{personBirthday.Value.ToString(GetFormat())}.json"; + internal static bool DoesBirthDateExits(Models.Properties.IStorage storage, Models.PersonBirthday personBirthday) => File.Exists(GetFileFullName(storage, personBirthday)); + internal static string GetFileFullName(Models.Properties.IStorage storage, Models.PersonBirthday personBirthday) => Path.Combine(storage.PeopleRootDirectory, "{}", GetFileName(personBirthday)); +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/PersonComment.cs b/Shared/Models/Stateless/Methods/PersonComment.cs new file mode 100644 index 0000000..d1fb129 --- /dev/null +++ b/Shared/Models/Stateless/Methods/PersonComment.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class PersonComment +{ + + internal static string GetDefaultValue() => string.Empty; // <{1}>PluralValue + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/PersonEmail.cs b/Shared/Models/Stateless/Methods/PersonEmail.cs new file mode 100644 index 0000000..e6dbf9a --- /dev/null +++ b/Shared/Models/Stateless/Methods/PersonEmail.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class PersonEmail +{ + + internal static string GetDefaultValue() => string.Empty; // <{1}>PluralValue + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/PersonId.cs b/Shared/Models/Stateless/Methods/PersonId.cs new file mode 100644 index 0000000..0c1c42e --- /dev/null +++ b/Shared/Models/Stateless/Methods/PersonId.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class PersonId +{ + + internal static long GetDefaultValue() => long.MinValue; // {{1}}SingletonValue + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/PersonName.cs b/Shared/Models/Stateless/Methods/PersonName.cs new file mode 100644 index 0000000..02726af --- /dev/null +++ b/Shared/Models/Stateless/Methods/PersonName.cs @@ -0,0 +1,60 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class PersonName +{ + + // ... + + internal static Models.PersonName Create(string name) + { + Models.PersonName result; + Models.PersonNameLast personNameLast; + Models.PersonNameAlias personNameAlias; + Models.PersonNameFirst personNameFirst; + Models.PersonNameMiddle personNameMiddle; + string[] segments = name.Split(' '); + if (segments.Length == 1) + { + personNameFirst = new(string.Empty); + personNameLast = new(string.Empty); + personNameMiddle = new(string.Empty); + personNameAlias = new(segments[0]); + } + else if (segments.Length == 2) + { + personNameFirst = new(segments[0]); + personNameLast = new(segments[1]); + personNameMiddle = new(string.Empty); + personNameAlias = new(string.Empty); + } + else if (segments.Length == 3 && segments[2] is "Jr." or "Jr" or "Sr") + { + personNameFirst = new(segments[0]); + personNameLast = new(segments[1]); + personNameMiddle = new(string.Empty); + personNameAlias = new(string.Join(' ', segments)); + } + else + { + string[] comment = name.Split(new string[] { " (" }, StringSplitOptions.None); + if (comment.Length == 1) + { + personNameFirst = new(segments[0]); + personNameLast = new(segments[^1]); + personNameMiddle = new(string.Empty); + personNameAlias = new(string.Join(' ', segments)); + } + else + { + segments = comment[0].Split(' '); + personNameFirst = new(segments[0]); + personNameLast = new(segments[^1]); + personNameMiddle = new(string.Empty); + personNameAlias = new(string.Concat(string.Join(' ', segments), " (", comment[1])); + } + } + result = new(personNameFirst, personNameMiddle, personNameLast, personNameAlias); + return result; + } + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/PersonNameAlias.cs b/Shared/Models/Stateless/Methods/PersonNameAlias.cs new file mode 100644 index 0000000..b0492e4 --- /dev/null +++ b/Shared/Models/Stateless/Methods/PersonNameAlias.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class PersonNameAlias +{ + + internal static string GetDefaultValue() => string.Empty; // {{1}}SingletonValue + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/PersonNameFirst.cs b/Shared/Models/Stateless/Methods/PersonNameFirst.cs new file mode 100644 index 0000000..d4a79da --- /dev/null +++ b/Shared/Models/Stateless/Methods/PersonNameFirst.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class PersonNameFirst +{ + + internal static string GetDefaultValue() => string.Empty; // {{1}}SingletonValue + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/PersonNameLast.cs b/Shared/Models/Stateless/Methods/PersonNameLast.cs new file mode 100644 index 0000000..9a6be21 --- /dev/null +++ b/Shared/Models/Stateless/Methods/PersonNameLast.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class PersonNameLast +{ + + internal static string GetDefaultValue() => string.Empty; // {{1}}SingletonValue + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/PersonNameMiddle.cs b/Shared/Models/Stateless/Methods/PersonNameMiddle.cs new file mode 100644 index 0000000..75c1e45 --- /dev/null +++ b/Shared/Models/Stateless/Methods/PersonNameMiddle.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class PersonNameMiddle +{ + + internal static string GetDefaultValue() => string.Empty; // {{1}}SingletonValue + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/PersonNumber.cs b/Shared/Models/Stateless/Methods/PersonNumber.cs new file mode 100644 index 0000000..ee6e223 --- /dev/null +++ b/Shared/Models/Stateless/Methods/PersonNumber.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class PersonNumber +{ + + internal static string GetDefaultValue() => string.Empty; // <{1}>PluralValue + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/PersonURL.cs b/Shared/Models/Stateless/Methods/PersonURL.cs new file mode 100644 index 0000000..53ffd76 --- /dev/null +++ b/Shared/Models/Stateless/Methods/PersonURL.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class PersonURL +{ + + internal static string GetDefaultValue() => string.Empty; // <{1}>PluralValue + + // ... + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/Storage.cs b/Shared/Models/Stateless/Methods/Storage.cs new file mode 100644 index 0000000..94718ac --- /dev/null +++ b/Shared/Models/Stateless/Methods/Storage.cs @@ -0,0 +1,27 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class Storage +{ + + // ... + + internal static bool WriteAllText(string path, string contents, bool compareBeforeWrite) + { + bool result; + string text; + if (!compareBeforeWrite) + result = true; + else + { + if (!File.Exists(path)) + text = string.Empty; + else + text = File.ReadAllText(path); + result = text != contents; + } + if (result) + File.WriteAllText(path, contents); + return result; + } + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/WorkingDirectory.cs b/Shared/Models/Stateless/Methods/WorkingDirectory.cs new file mode 100644 index 0000000..95a85fa --- /dev/null +++ b/Shared/Models/Stateless/Methods/WorkingDirectory.cs @@ -0,0 +1,50 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class WorkingDirectory +{ + + internal static string GetWorkingDirectory(string? executingAssemblyName, string subDirectoryName) + { + string result = string.Empty; + if (executingAssemblyName is null) + throw new Exception(); + string traceFile; + List directories = new(); + Environment.SpecialFolder[] specialFolders = new Environment.SpecialFolder[] + { + Environment.SpecialFolder.LocalApplicationData, + Environment.SpecialFolder.ApplicationData, + Environment.SpecialFolder.History, + Environment.SpecialFolder.CommonApplicationData, + Environment.SpecialFolder.InternetCache + }; + foreach (Environment.SpecialFolder specialFolder in specialFolders) + directories.Add(Path.Combine(Environment.GetFolderPath(specialFolder), subDirectoryName, executingAssemblyName)); + foreach (string directory in directories) + { + for (int i = 1; i < 3; i++) + { + if (i == 1) + result = directory; + else + result = string.Concat("D", directory[1..]); + try + { + if (!Directory.Exists(result)) + _ = Directory.CreateDirectory(result); + traceFile = string.Concat(result, @"\", DateTime.Now.Ticks, ".txt"); + File.WriteAllText(traceFile, traceFile); + File.Delete(traceFile); + break; + } + catch (Exception) { result = string.Empty; } + } + if (!string.IsNullOrEmpty(result)) + break; + } + if (string.IsNullOrEmpty(result)) + throw new Exception("Unable to set working directory!"); + return result; + } + +} \ No newline at end of file diff --git a/Shared/Models/Storage.cs b/Shared/Models/Storage.cs new file mode 100644 index 0000000..073f121 --- /dev/null +++ b/Shared/Models/Storage.cs @@ -0,0 +1,79 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class Storage : Properties.IStorage +{ + + protected string _DistanceResultRootDirectory; + protected string _FaceRootDirectory; + protected string _IndexInfoRootDirectory; + protected string _MetadataRootDirectory; + protected string _PeopleRootDirectory; + protected string _ResizeRootDirectory; + protected string _RootDirectory; + protected string _RootResultsDirectory; + protected string _UrlRoot; + public string DistanceResultRootDirectory => _DistanceResultRootDirectory; + public string FaceRootDirectory => _FaceRootDirectory; + public string IndexInfoRootDirectory => _IndexInfoRootDirectory; + public string MetadataRootDirectory => _MetadataRootDirectory; + public string PeopleRootDirectory => _PeopleRootDirectory; + public string ResizeRootDirectory => _ResizeRootDirectory; + public string RootDirectory => _RootDirectory; + public string RootResultsDirectory => _RootResultsDirectory; + public string UrlRoot => _UrlRoot; + + [JsonConstructor] + public Storage(string distanceResultRootDirectory, string faceRootDirectory, string indexInfoRootDirectory, string metadataRootDirectory, string peopleRootDirectory, string resizeRootDirectory, string rootDirectory, string rootResultsDirectory, string urlRoot) + { + _DistanceResultRootDirectory = distanceResultRootDirectory; + _FaceRootDirectory = faceRootDirectory; + _IndexInfoRootDirectory = indexInfoRootDirectory; + _MetadataRootDirectory = metadataRootDirectory; + _PeopleRootDirectory = peopleRootDirectory; + _ResizeRootDirectory = resizeRootDirectory; + _RootDirectory = rootDirectory; + _RootResultsDirectory = rootResultsDirectory; + _UrlRoot = urlRoot; + string fullRootResultsDirectory; + if (rootResultsDirectory.StartsWith(rootDirectory)) + fullRootResultsDirectory = rootResultsDirectory; + else + fullRootResultsDirectory = string.Concat(rootDirectory, rootResultsDirectory); + _RootResultsDirectory = fullRootResultsDirectory; + if (!distanceResultRootDirectory.StartsWith(rootDirectory)) + _DistanceResultRootDirectory = string.Concat(fullRootResultsDirectory, distanceResultRootDirectory); + if (!faceRootDirectory.StartsWith(rootDirectory)) + _FaceRootDirectory = string.Concat(fullRootResultsDirectory, faceRootDirectory); + if (!indexInfoRootDirectory.StartsWith(rootDirectory)) + _IndexInfoRootDirectory = string.Concat(fullRootResultsDirectory, indexInfoRootDirectory); + if (!metadataRootDirectory.StartsWith(rootDirectory)) + _MetadataRootDirectory = string.Concat(fullRootResultsDirectory, metadataRootDirectory); + if (!peopleRootDirectory.StartsWith(rootDirectory)) + _PeopleRootDirectory = string.Concat(fullRootResultsDirectory, peopleRootDirectory); + if (!resizeRootDirectory.StartsWith(rootDirectory)) + _ResizeRootDirectory = string.Concat(fullRootResultsDirectory, resizeRootDirectory); + } + + public Storage(string rootDirectory, string rootResultsDirectory, string peopleRootDirectory) + { + _DistanceResultRootDirectory = "distanceResultRootDirectory"; + _FaceRootDirectory = "faceRootDirectory"; + _IndexInfoRootDirectory = "indexInfoRootDirectory"; + _MetadataRootDirectory = "metadataRootDirectory"; + _PeopleRootDirectory = peopleRootDirectory; + _ResizeRootDirectory = "resizeRootDirectory"; + _RootDirectory = rootDirectory; + _RootResultsDirectory = rootResultsDirectory; + _UrlRoot = "urlRoot"; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } // ... + +} \ No newline at end of file diff --git a/Shared/Phares/Shared/IsEnvironment.cs b/Shared/Phares/Shared/IsEnvironment.cs new file mode 100644 index 0000000..f5f24a9 --- /dev/null +++ b/Shared/Phares/Shared/IsEnvironment.cs @@ -0,0 +1,167 @@ +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace Phares.Shared; + +public class IsEnvironment +{ + + public enum Name + { + LinuxDevelopment, + LinuxProduction, + LinuxStaging, + OSXDevelopment, + OSXProduction, + OSXStaging, + WindowsDevelopment, + WindowsProduction, + WindowsStaging + } + + public bool DebuggerWasAttachedDuringConstructor { get; private set; } + public bool Development { get; private set; } + public bool Linux { get; private set; } + public bool OSX { get; private set; } + public bool Production { get; private set; } + public bool Staging { get; private set; } + public bool Windows { get; private set; } + public string Profile { get; private set; } + public string AppSettingsFileName { get; private set; } + public string? ASPNetCoreEnvironment { get; private set; } + + public IsEnvironment(string testCategory) + { + if (testCategory.EndsWith(".json")) + { + Production = testCategory == "appsettings.json"; + Staging = testCategory.EndsWith(nameof(Staging)); + OSX = RuntimeInformation.IsOSPlatform(OSPlatform.OSX); + Development = testCategory.EndsWith(nameof(Development)); + Linux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); + DebuggerWasAttachedDuringConstructor = Debugger.IsAttached; + Windows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + ASPNetCoreEnvironment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"); + } + else + { + DebuggerWasAttachedDuringConstructor = Debugger.IsAttached; + OSX = !string.IsNullOrEmpty(testCategory) && testCategory.StartsWith(nameof(OSX)); + ASPNetCoreEnvironment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"); + Linux = !string.IsNullOrEmpty(testCategory) && testCategory.StartsWith(nameof(Linux)); + Staging = !string.IsNullOrEmpty(testCategory) && testCategory.EndsWith(nameof(Staging)); + Windows = !string.IsNullOrEmpty(testCategory) && testCategory.StartsWith(nameof(Windows)); + Production = !string.IsNullOrEmpty(testCategory) && testCategory.EndsWith(nameof(Production)); + Development = !string.IsNullOrEmpty(testCategory) && testCategory.EndsWith(nameof(Development)); + } + Profile = GetProfile(); + AppSettingsFileName = GetAppSettingsFileName(processesCount: null); + } + + public IsEnvironment(bool isDevelopment, bool isStaging, bool isProduction) + { + Staging = isStaging; + Production = isProduction; + Development = isDevelopment; + OSX = RuntimeInformation.IsOSPlatform(OSPlatform.OSX); + Linux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); + DebuggerWasAttachedDuringConstructor = Debugger.IsAttached; + Windows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + ASPNetCoreEnvironment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"); + Profile = GetProfile(); + AppSettingsFileName = GetAppSettingsFileName(processesCount: null); + } + + public IsEnvironment(int? processesCount, bool nullASPNetCoreEnvironmentIsDevelopment, bool nullASPNetCoreEnvironmentIsProduction) + { + OSX = RuntimeInformation.IsOSPlatform(OSPlatform.OSX); + Linux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); + DebuggerWasAttachedDuringConstructor = Debugger.IsAttached; + Windows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + ASPNetCoreEnvironment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"); + if (nullASPNetCoreEnvironmentIsDevelopment && nullASPNetCoreEnvironmentIsProduction) + throw new Exception(); + else if (string.IsNullOrEmpty(ASPNetCoreEnvironment) && nullASPNetCoreEnvironmentIsProduction) + Production = true; + else if (string.IsNullOrEmpty(ASPNetCoreEnvironment) && nullASPNetCoreEnvironmentIsDevelopment) + Development = true; + else if (string.IsNullOrEmpty(ASPNetCoreEnvironment) && !nullASPNetCoreEnvironmentIsDevelopment && !nullASPNetCoreEnvironmentIsProduction) + throw new Exception(); + else + { + Staging = ASPNetCoreEnvironment is not null && ASPNetCoreEnvironment.EndsWith(nameof(Staging)); + Production = ASPNetCoreEnvironment is not null && ASPNetCoreEnvironment.EndsWith(nameof(Production)); + Development = ASPNetCoreEnvironment is not null && ASPNetCoreEnvironment.EndsWith(nameof(Development)); + } + Profile = GetProfile(); + AppSettingsFileName = GetAppSettingsFileName(processesCount); + } + + private string GetProfile() + { + string result; + if (Windows && Production) + result = nameof(Production); + else if (Windows && Staging) + result = nameof(Staging); + else if (Windows && Development) + result = nameof(Development); + else if (Linux && Production) + result = nameof(Name.LinuxProduction); + else if (Linux && Staging) + result = nameof(Name.LinuxStaging); + else if (Linux && Development) + result = nameof(Name.LinuxDevelopment); + else if (OSX && Production) + result = nameof(Name.OSXProduction); + else if (OSX && Staging) + result = nameof(Name.OSXStaging); + else if (OSX && Development) + result = nameof(Name.OSXDevelopment); + else + throw new Exception(); + return result; + } + + private string GetAppSettingsFileName(int? processesCount) + { + string result; + if (Production) + { + if (processesCount is null) + result = "appsettings.json"; + else + result = $"appsettings.{processesCount}.json"; + } + else + { + string environment; + if (Staging) + environment = nameof(Staging); + else if (Development) + environment = nameof(Development); + else + throw new Exception(); + if (processesCount is null) + result = $"appsettings.{environment}.json"; + else + result = $"appsettings.{environment}.{processesCount}.json"; + } + return result; + } + + public static string GetEnvironmentName(IsEnvironment isEnvironment) + { + string result; + if (isEnvironment.Windows) + result = nameof(Windows); + else if (isEnvironment.Linux) + result = nameof(Linux); + else if (isEnvironment.OSX) + result = nameof(OSX); + else + throw new Exception(); + return result; + } + +} \ No newline at end of file diff --git a/Shared/Phares/Shared/RijndaelEncryption.cs b/Shared/Phares/Shared/RijndaelEncryption.cs new file mode 100644 index 0000000..1a9a074 --- /dev/null +++ b/Shared/Phares/Shared/RijndaelEncryption.cs @@ -0,0 +1,93 @@ +#pragma warning disable SYSLIB0022 + +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; + +namespace Phares.Shared; + +public static class RijndaelEncryption +{ + /// + /// Change the Inputkey GUID when you use this code in your own program. + /// Keep this inputkey very safe and prevent someone from decoding it some way!! + /// Generated 2021-08-10 + /// + internal const string _Inputkey = "970CCEF6-4307-4F6A-9AC8-377DADB889BD"; + + /// + /// Encrypt the given text and give the byte array back as a BASE64 string + /// + /// The text to encrypt + /// The pasword salt + /// The encrypted text + public static string Encrypt(string text, string salt) + { + string result; + if (string.IsNullOrEmpty(text)) + throw new ArgumentNullException(nameof(text)); + RijndaelManaged aesAlg = NewRijndaelManaged(salt); + ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV); + MemoryStream msEncrypt = new(); + using (CryptoStream csEncrypt = new(msEncrypt, encryptor, CryptoStreamMode.Write)) + using (StreamWriter swEncrypt = new(csEncrypt)) + swEncrypt.Write(text); + result = Convert.ToBase64String(msEncrypt.ToArray()); + return result; + } + + /// + /// Checks if a string is base64 encoded + /// + /// The base64 encoded string + /// + public static bool IsBase64String(string base64String) + { + bool result; + base64String = base64String.Trim(); + result = (base64String.Length % 4 == 0) && Regex.IsMatch(base64String, @"^[a-zA-Z0-9\+/]*={0,3}$", RegexOptions.None); + return result; + } + + /// + /// Decrypts the given text + /// + /// The encrypted BASE64 text + /// The pasword salt + /// De gedecrypte text + public static string Decrypt(string cipherText, string salt) + { + if (string.IsNullOrEmpty(cipherText)) + throw new ArgumentNullException(nameof(cipherText)); + if (!IsBase64String(cipherText)) + throw new Exception("The cipherText input parameter is not base64 encoded"); + string text; + RijndaelManaged aesAlg = NewRijndaelManaged(salt); + ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV); + byte[] cipher = Convert.FromBase64String(cipherText); + using (MemoryStream msDecrypt = new(cipher)) + { + using CryptoStream csDecrypt = new(msDecrypt, decryptor, CryptoStreamMode.Read); + using StreamReader srDecrypt = new(csDecrypt); + text = srDecrypt.ReadToEnd(); + } + return text; + } + + /// + /// Create a new RijndaelManaged class and initialize it + /// + /// The pasword salt + /// + private static RijndaelManaged NewRijndaelManaged(string salt) + { + if (salt == null) + throw new ArgumentNullException(nameof(salt)); + byte[] saltBytes = Encoding.ASCII.GetBytes(salt); + Rfc2898DeriveBytes key = new(_Inputkey, saltBytes); + RijndaelManaged aesAlg = new(); + aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8); + aesAlg.IV = key.GetBytes(aesAlg.BlockSize / 8); + return aesAlg; + } +} \ No newline at end of file diff --git a/Shared/Sample-Data/MetadataFile.cs b/Shared/Sample-Data/MetadataFile.cs new file mode 100644 index 0000000..0b542f7 --- /dev/null +++ b/Shared/Sample-Data/MetadataFile.cs @@ -0,0 +1 @@ +namespace View_by_Distance.Shared.Sample_Data; \ No newline at end of file diff --git a/Shared/Sample-Data/People.cs b/Shared/Sample-Data/People.cs new file mode 100644 index 0000000..0b542f7 --- /dev/null +++ b/Shared/Sample-Data/People.cs @@ -0,0 +1 @@ +namespace View_by_Distance.Shared.Sample_Data; \ No newline at end of file diff --git a/Shared/Sample-Data/PropertyCollectionFile.cs b/Shared/Sample-Data/PropertyCollectionFile.cs new file mode 100644 index 0000000..0b542f7 --- /dev/null +++ b/Shared/Sample-Data/PropertyCollectionFile.cs @@ -0,0 +1 @@ +namespace View_by_Distance.Shared.Sample_Data; \ No newline at end of file diff --git a/Shared/Sample-Data/metadataFile.json b/Shared/Sample-Data/metadataFile.json new file mode 100644 index 0000000..f41f8e3 --- /dev/null +++ b/Shared/Sample-Data/metadataFile.json @@ -0,0 +1,80 @@ +[ + [ + { + "OriginalIndex": 0, + "PathWithoutBracketsPadded": "MetadataFile_.Id_________", + "Name": "Value", + "JsonElementAsString": "/bla/FileName.json", + "KeyWithoutBrackets": "MetadataFile.Id.Value", + "IsValueNode": true, + "IsCollectionNode": false, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": false, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "MetadataFileId", + "Type": "string", + "SuggestedType": "string", + "JoinedValues": "001) ...", + "Flag": 6 + } + ], + [ + { + "OriginalIndex": 1, + "PathWithoutBracketsPadded": "MetadataFile_.Collection_", + "Name": "Value", + "JsonElementAsString": "json", + "KeyWithoutBrackets": "MetadataFile.Collection.Value", + "IsValueNode": true, + "IsCollectionNode": false, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": false, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "MetadataFileCollection", + "Type": "string", + "SuggestedType": "string", + "JoinedValues": "001) ...", + "Flag": 6 + } + ], + [ + { + "OriginalIndex": 0, + "PathWithoutBracketsPadded": "MetadataFile_", + "Name": "Id", + "JsonElementAsString": "/bla/FileName.json", + "KeyWithoutBrackets": "MetadataFile.Id.Value", + "IsValueNode": false, + "IsCollectionNode": false, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": true, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "MetadataFile", + "Type": "MetadataFileId", + "SuggestedType": "string", + "JoinedValues": "001) \u0022/bla/FileName.json\u0022", + "Flag": 4 + }, + { + "OriginalIndex": 1, + "PathWithoutBracketsPadded": "MetadataFile_", + "Name": "Collection", + "JsonElementAsString": "json", + "KeyWithoutBrackets": "MetadataFile.Collection.Value", + "IsValueNode": false, + "IsCollectionNode": false, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": true, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "MetadataFile", + "Type": "MetadataFileCollection", + "SuggestedType": "string", + "JoinedValues": "001) \u0022json\u0022", + "Flag": 4 + } + ] +] \ No newline at end of file diff --git a/Shared/Sample-Data/metadataFiles.json b/Shared/Sample-Data/metadataFiles.json new file mode 100644 index 0000000..e0dec08 --- /dev/null +++ b/Shared/Sample-Data/metadataFiles.json @@ -0,0 +1,18 @@ +[ + { + "Id": { + "Value": "/bla/FileName.json" + }, + "Collection": { + "Value": "json" + } + }, + { + "Id": { + "Value": "/bla/FileNameB.json" + }, + "Collection": { + "Value": "jsonB" + } + } +] \ No newline at end of file diff --git a/Shared/Sample-Data/people.json b/Shared/Sample-Data/people.json new file mode 100644 index 0000000..aa61c76 --- /dev/null +++ b/Shared/Sample-Data/people.json @@ -0,0 +1,63 @@ +[ + { + "Id": { + "Value": 21474836471 + }, + "Name": { + "First": { + "Value": "Leslie" + }, + "Middle": { + "Value": "Michael" + }, + "Last": { + "Value": "Phares" + }, + "Alias": { + "Value": "Mike Jr." + } + }, + "Birthday": { + "Value": "1980-01-17T00:00:00" + }, + "Comments": [ + { + "Value": "Hello" + }, + { + "Value": "Bye" + } + ], + "URLs": [ + { + "Value": "http:\\localhost" + } + ], + "Numbers": [ + { + "Value": "5053637467" + } + ], + "Emails": [ + { + "Value": "mikepharesjr@msn.com" + } + ], + "Addresses": [ + { + "Street": { + "Value": "3757 W Whitman Dr" + }, + "City": { + "Value": "Anthem" + }, + "State": { + "Value": "Arizona" + }, + "ZipCode": { + "Value": "85086" + } + } + ] + } +] \ No newline at end of file diff --git a/Shared/Sample-Data/person.json b/Shared/Sample-Data/person.json new file mode 100644 index 0000000..03885f6 --- /dev/null +++ b/Shared/Sample-Data/person.json @@ -0,0 +1,576 @@ +[ + [ + { + "OriginalIndex": 2, + "PathWithoutBracketsPadded": "Person_.Name______.Middle__", + "Name": "Value", + "JsonElementAsString": "Michael", + "KeyWithoutBrackets": "Person.Name.Middle.Value", + "IsValueNode": true, + "IsCollectionNode": false, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": false, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "PersonNameMiddle", + "Type": "string", + "SuggestedType": "string", + "JoinedValues": "001) ...", + "Flag": 6 + } + ], + [ + { + "OriginalIndex": 3, + "PathWithoutBracketsPadded": "Person_.Name______.Last____", + "Name": "Value", + "JsonElementAsString": "Phares", + "KeyWithoutBrackets": "Person.Name.Last.Value", + "IsValueNode": true, + "IsCollectionNode": false, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": false, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "PersonNameLast", + "Type": "string", + "SuggestedType": "string", + "JoinedValues": "001) ...", + "Flag": 6 + } + ], + [ + { + "OriginalIndex": 1, + "PathWithoutBracketsPadded": "Person_.Name______.First___", + "Name": "Value", + "JsonElementAsString": "Leslie", + "KeyWithoutBrackets": "Person.Name.First.Value", + "IsValueNode": true, + "IsCollectionNode": false, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": false, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "PersonNameFirst", + "Type": "string", + "SuggestedType": "string", + "JoinedValues": "001) ...", + "Flag": 6 + } + ], + [ + { + "OriginalIndex": 4, + "PathWithoutBracketsPadded": "Person_.Name______.Alias___", + "Name": "Value", + "JsonElementAsString": "Mike Jr.", + "KeyWithoutBrackets": "Person.Name.Alias.Value", + "IsValueNode": true, + "IsCollectionNode": false, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": false, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "PersonNameAlias", + "Type": "string", + "SuggestedType": "string", + "JoinedValues": "001) ...", + "Flag": 6 + } + ], + [ + { + "OriginalIndex": 14, + "PathWithoutBracketsPadded": "Person_.Addresses_.ZipCode_", + "Name": "Value", + "JsonElementAsString": "85086", + "KeyWithoutBrackets": "Person.Addresses.ZipCode.Value", + "IsValueNode": true, + "IsCollectionNode": false, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": false, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "PersonAddressZipCode", + "Type": "string", + "SuggestedType": "string", + "JoinedValues": "001) ...", + "Flag": 6 + } + ], + [ + { + "OriginalIndex": 11, + "PathWithoutBracketsPadded": "Person_.Addresses_.Street__", + "Name": "Value", + "JsonElementAsString": "3757 W Whitman Dr", + "KeyWithoutBrackets": "Person.Addresses.Street.Value", + "IsValueNode": true, + "IsCollectionNode": false, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": false, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "PersonAddressStreet", + "Type": "string", + "SuggestedType": "string", + "JoinedValues": "001) ...", + "Flag": 6 + } + ], + [ + { + "OriginalIndex": 13, + "PathWithoutBracketsPadded": "Person_.Addresses_.State___", + "Name": "Value", + "JsonElementAsString": "Arizona", + "KeyWithoutBrackets": "Person.Addresses.State.Value", + "IsValueNode": true, + "IsCollectionNode": false, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": false, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "PersonAddressState", + "Type": "string", + "SuggestedType": "string", + "JoinedValues": "001) ...", + "Flag": 6 + } + ], + [ + { + "OriginalIndex": 12, + "PathWithoutBracketsPadded": "Person_.Addresses_.City____", + "Name": "Value", + "JsonElementAsString": "Anthem", + "KeyWithoutBrackets": "Person.Addresses.City.Value", + "IsValueNode": true, + "IsCollectionNode": false, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": false, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "PersonAddressCity", + "Type": "string", + "SuggestedType": "string", + "JoinedValues": "001) ...", + "Flag": 6 + } + ], + [ + { + "OriginalIndex": 8, + "PathWithoutBracketsPadded": "Person_.URLs______", + "Name": "Value", + "JsonElementAsString": "http:\\localhost", + "KeyWithoutBrackets": "Person.URLs.Value", + "IsValueNode": true, + "IsCollectionNode": true, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": false, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "PersonURL", + "Type": "string", + "SuggestedType": "string", + "JoinedValues": "001) ...", + "Flag": 7 + } + ], + [ + { + "OriginalIndex": 9, + "PathWithoutBracketsPadded": "Person_.Numbers___", + "Name": "Value", + "JsonElementAsString": "5053637467", + "KeyWithoutBrackets": "Person.Numbers.Value", + "IsValueNode": true, + "IsCollectionNode": true, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": false, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "PersonNumber", + "Type": "string", + "SuggestedType": "string", + "JoinedValues": "001) ...", + "Flag": 7 + } + ], + [ + { + "OriginalIndex": 1, + "PathWithoutBracketsPadded": "Person_.Name______", + "Name": "First", + "JsonElementAsString": "Leslie", + "KeyWithoutBrackets": "Person.Name.First.Value", + "IsValueNode": false, + "IsCollectionNode": false, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": true, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "PersonName", + "Type": "PersonNameFirst", + "SuggestedType": "string", + "JoinedValues": "001) \u0022Leslie\u0022", + "Flag": 4 + }, + { + "OriginalIndex": 2, + "PathWithoutBracketsPadded": "Person_.Name______", + "Name": "Middle", + "JsonElementAsString": "Michael", + "KeyWithoutBrackets": "Person.Name.Middle.Value", + "IsValueNode": false, + "IsCollectionNode": false, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": true, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "PersonName", + "Type": "PersonNameMiddle", + "SuggestedType": "string", + "JoinedValues": "001) \u0022Michael\u0022", + "Flag": 4 + }, + { + "OriginalIndex": 3, + "PathWithoutBracketsPadded": "Person_.Name______", + "Name": "Last", + "JsonElementAsString": "Phares", + "KeyWithoutBrackets": "Person.Name.Last.Value", + "IsValueNode": false, + "IsCollectionNode": false, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": true, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "PersonName", + "Type": "PersonNameLast", + "SuggestedType": "string", + "JoinedValues": "001) \u0022Phares\u0022", + "Flag": 4 + }, + { + "OriginalIndex": 4, + "PathWithoutBracketsPadded": "Person_.Name______", + "Name": "Alias", + "JsonElementAsString": "Mike Jr.", + "KeyWithoutBrackets": "Person.Name.Alias.Value", + "IsValueNode": false, + "IsCollectionNode": false, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": true, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "PersonName", + "Type": "PersonNameAlias", + "SuggestedType": "string", + "JoinedValues": "001) \u0022Mike Jr.\u0022", + "Flag": 4 + } + ], + [ + { + "OriginalIndex": 0, + "PathWithoutBracketsPadded": "Person_.Id________", + "Name": "Value", + "JsonElementAsString": "21474836471", + "KeyWithoutBrackets": "Person.Id.Value", + "IsValueNode": true, + "IsCollectionNode": false, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": false, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "PersonId", + "Type": "long", + "SuggestedType": "long", + "JoinedValues": "001) ...", + "Flag": 6 + } + ], + [ + { + "OriginalIndex": 10, + "PathWithoutBracketsPadded": "Person_.Emails____", + "Name": "Value", + "JsonElementAsString": "mikepharesjr@msn.com", + "KeyWithoutBrackets": "Person.Emails.Value", + "IsValueNode": true, + "IsCollectionNode": true, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": false, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "PersonEmail", + "Type": "string", + "SuggestedType": "string", + "JoinedValues": "001) ...", + "Flag": 7 + } + ], + [ + { + "OriginalIndex": 6, + "PathWithoutBracketsPadded": "Person_.Comments__", + "Name": "Value", + "JsonElementAsString": "Hello", + "KeyWithoutBrackets": "Person.Comments.Value", + "IsValueNode": true, + "IsCollectionNode": true, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": false, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "PersonComment", + "Type": "string", + "SuggestedType": "string", + "JoinedValues": "002) ...", + "Flag": 7 + } + ], + [ + { + "OriginalIndex": 5, + "PathWithoutBracketsPadded": "Person_.Birthday__", + "Name": "Value", + "JsonElementAsString": "1980-01-17T00:00:00", + "KeyWithoutBrackets": "Person.Birthday.Value", + "IsValueNode": true, + "IsCollectionNode": false, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": false, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "PersonBirthday", + "Type": "DateTime", + "SuggestedType": "DateTime", + "JoinedValues": "001) ...", + "Flag": 6 + } + ], + [ + { + "OriginalIndex": 11, + "PathWithoutBracketsPadded": "Person_.Addresses_", + "Name": "Street", + "JsonElementAsString": "3757 W Whitman Dr", + "KeyWithoutBrackets": "Person.Addresses.Street.Value", + "IsValueNode": false, + "IsCollectionNode": false, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": true, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "PersonAddress", + "Type": "PersonAddressStreet", + "SuggestedType": "string", + "JoinedValues": "001) \u00223757 W Whitman Dr\u0022", + "Flag": 4 + }, + { + "OriginalIndex": 12, + "PathWithoutBracketsPadded": "Person_.Addresses_", + "Name": "City", + "JsonElementAsString": "Anthem", + "KeyWithoutBrackets": "Person.Addresses.City.Value", + "IsValueNode": false, + "IsCollectionNode": false, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": true, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "PersonAddress", + "Type": "PersonAddressCity", + "SuggestedType": "string", + "JoinedValues": "001) \u0022Anthem\u0022", + "Flag": 4 + }, + { + "OriginalIndex": 13, + "PathWithoutBracketsPadded": "Person_.Addresses_", + "Name": "State", + "JsonElementAsString": "Arizona", + "KeyWithoutBrackets": "Person.Addresses.State.Value", + "IsValueNode": false, + "IsCollectionNode": false, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": true, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "PersonAddress", + "Type": "PersonAddressState", + "SuggestedType": "string", + "JoinedValues": "001) \u0022Arizona\u0022", + "Flag": 4 + }, + { + "OriginalIndex": 14, + "PathWithoutBracketsPadded": "Person_.Addresses_", + "Name": "ZipCode", + "JsonElementAsString": "85086", + "KeyWithoutBrackets": "Person.Addresses.ZipCode.Value", + "IsValueNode": false, + "IsCollectionNode": false, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": true, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "PersonAddress", + "Type": "PersonAddressZipCode", + "SuggestedType": "string", + "JoinedValues": "001) \u002285086\u0022", + "Flag": 4 + } + ], + [ + { + "OriginalIndex": 0, + "PathWithoutBracketsPadded": "Person_", + "Name": "Id", + "JsonElementAsString": "21474836471", + "KeyWithoutBrackets": "Person.Id.Value", + "IsValueNode": false, + "IsCollectionNode": false, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": true, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "Person", + "Type": "PersonId", + "SuggestedType": "long", + "JoinedValues": "001) \u002221474836471\u0022", + "Flag": 4 + }, + { + "OriginalIndex": 4, + "PathWithoutBracketsPadded": "Person_", + "Name": "Name", + "JsonElementAsString": "Mike Jr.", + "KeyWithoutBrackets": "Person.Name.Alias.Value", + "IsValueNode": false, + "IsCollectionNode": false, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": false, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": true, + "PathWithoutBracketsSingularized": "Person", + "Type": "PersonName", + "SuggestedType": "JsonValueKind.Object", + "JoinedValues": "", + "Flag": 2 + }, + { + "OriginalIndex": 5, + "PathWithoutBracketsPadded": "Person_", + "Name": "Birthday", + "JsonElementAsString": "1980-01-17T00:00:00", + "KeyWithoutBrackets": "Person.Birthday.Value", + "IsValueNode": false, + "IsCollectionNode": false, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": true, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "Person", + "Type": "PersonBirthday", + "SuggestedType": "DateTime", + "JoinedValues": "001) \u00221980-01-17T00:00:00\u0022", + "Flag": 4 + }, + { + "OriginalIndex": 6, + "PathWithoutBracketsPadded": "Person_", + "Name": "Comments", + "JsonElementAsString": "Hello", + "KeyWithoutBrackets": "Person.Comments.Value", + "IsValueNode": false, + "IsCollectionNode": true, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": true, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "Person", + "Type": "PersonComment", + "SuggestedType": "string", + "JoinedValues": "002) \u0022Bye\u0022, \u0022Hello\u0022", + "Flag": 5 + }, + { + "OriginalIndex": 8, + "PathWithoutBracketsPadded": "Person_", + "Name": "URLs", + "JsonElementAsString": "http:\\localhost", + "KeyWithoutBrackets": "Person.URLs.Value", + "IsValueNode": false, + "IsCollectionNode": true, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": true, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "Person", + "Type": "PersonURL", + "SuggestedType": "string", + "JoinedValues": "001) \u0022http:\\localhost\u0022", + "Flag": 5 + }, + { + "OriginalIndex": 9, + "PathWithoutBracketsPadded": "Person_", + "Name": "Numbers", + "JsonElementAsString": "5053637467", + "KeyWithoutBrackets": "Person.Numbers.Value", + "IsValueNode": false, + "IsCollectionNode": true, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": true, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "Person", + "Type": "PersonNumber", + "SuggestedType": "string", + "JoinedValues": "001) \u00225053637467\u0022", + "Flag": 5 + }, + { + "OriginalIndex": 10, + "PathWithoutBracketsPadded": "Person_", + "Name": "Emails", + "JsonElementAsString": "mikepharesjr@msn.com", + "KeyWithoutBrackets": "Person.Emails.Value", + "IsValueNode": false, + "IsCollectionNode": true, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": true, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "Person", + "Type": "PersonEmail", + "SuggestedType": "string", + "JoinedValues": "001) \u0022mikepharesjr@msn.com\u0022", + "Flag": 5 + }, + { + "OriginalIndex": 12, + "PathWithoutBracketsPadded": "Person_", + "Name": "Addresses", + "JsonElementAsString": "Anthem", + "KeyWithoutBrackets": "Person.Addresses.City.Value", + "IsValueNode": false, + "IsCollectionNode": true, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": false, + "IsJsonValueKindArray": true, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "Person", + "Type": "PersonAddress", + "SuggestedType": "JsonValueKind.Array", + "JoinedValues": "", + "Flag": 3 + } + ] +] \ No newline at end of file diff --git a/Shared/Sample-Data/propertyCollectionFile.json b/Shared/Sample-Data/propertyCollectionFile.json new file mode 100644 index 0000000..b546814 --- /dev/null +++ b/Shared/Sample-Data/propertyCollectionFile.json @@ -0,0 +1,80 @@ +[ + [ + { + "OriginalIndex": 1, + "PathWithoutBracketsPadded": "PropertyCollectionFile_.Properties_", + "Name": "Value", + "JsonElementAsString": "json", + "KeyWithoutBrackets": "PropertyCollectionFile.Properties.Value", + "IsValueNode": true, + "IsCollectionNode": true, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": false, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "PropertyCollectionFileProperty", + "Type": "Shared.Models.Property", + "SuggestedType": "Shared.Models.Property", + "JoinedValues": "001) ...", + "Flag": 7 + } + ], + [ + { + "OriginalIndex": 0, + "PathWithoutBracketsPadded": "PropertyCollectionFile_.Id_________", + "Name": "Value", + "JsonElementAsString": "/bla/FileName.json", + "KeyWithoutBrackets": "PropertyCollectionFile.Id.Value", + "IsValueNode": true, + "IsCollectionNode": false, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": false, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "PropertyCollectionFileId", + "Type": "string", + "SuggestedType": "string", + "JoinedValues": "001) ...", + "Flag": 6 + } + ], + [ + { + "OriginalIndex": 0, + "PathWithoutBracketsPadded": "PropertyCollectionFile_", + "Name": "Id", + "JsonElementAsString": "/bla/FileName.json", + "KeyWithoutBrackets": "PropertyCollectionFile.Id.Value", + "IsValueNode": false, + "IsCollectionNode": false, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": true, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "PropertyCollectionFile", + "Type": "PropertyCollectionFileId", + "SuggestedType": "string", + "JoinedValues": "001) \u0022/bla/FileName.json\u0022", + "Flag": 4 + }, + { + "OriginalIndex": 1, + "PathWithoutBracketsPadded": "PropertyCollectionFile_", + "Name": "Properties", + "JsonElementAsString": "json", + "KeyWithoutBrackets": "PropertyCollectionFile.Properties.Value", + "IsValueNode": false, + "IsCollectionNode": true, + "DoesNotHaveValueNode": false, + "IsLastNodeOrJustBeforeValue": true, + "IsJsonValueKindArray": false, + "IsJsonValueKindObject": false, + "PathWithoutBracketsSingularized": "PropertyCollectionFile", + "Type": "PropertyCollectionFileProperty", + "SuggestedType": "Shared.Models.Property", + "JoinedValues": "001) \u0022json\u0022", + "Flag": 5 + } + ] +] \ No newline at end of file diff --git a/Shared/Sample-Data/propertyCollectionFiles.json b/Shared/Sample-Data/propertyCollectionFiles.json new file mode 100644 index 0000000..9c8a33a --- /dev/null +++ b/Shared/Sample-Data/propertyCollectionFiles.json @@ -0,0 +1,22 @@ +[ + { + "Id": { + "Value": "/bla/FileName.json" + }, + "Properties": [ + { + "Value": "json" + } + ] + }, + { + "Id": { + "Value": "/bla/FileNameB.json" + }, + "Properties": [ + { + "Value": "jsonB" + } + ] + } +] \ No newline at end of file diff --git a/Shared/View-by-Distance.Shared.csproj b/Shared/View-by-Distance.Shared.csproj new file mode 100644 index 0000000..0f827ef --- /dev/null +++ b/Shared/View-by-Distance.Shared.csproj @@ -0,0 +1,40 @@ + + + enable + 10.0 + enable + win-x64 + net6.0 + + + Phares.View.by.Distance.Shared + false + 5.0.402.104 + Mike Phares + Phares + true + snupkg + + + true + true + true + + + Windows + + + OSX + + + Linux + + + + + + + + + + \ No newline at end of file diff --git a/View-by-Distance-MKLink-Console.sln b/View-by-Distance-MKLink-Console.sln new file mode 100644 index 0000000..5d34c89 --- /dev/null +++ b/View-by-Distance-MKLink-Console.sln @@ -0,0 +1,76 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "View-by-Distance.Shared", "shared\View-by-Distance.Shared.csproj", "{1D231660-33B4-4763-9C9F-C6ACC8BA600D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Compare", "Compare\Compare.csproj", "{372BFEDC-8E9C-4DDE-AD8D-66D9CE0670E1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Date-Group", "Date-Group\Date-Group.csproj", "{DFEDB5F9-AFFC-40A2-9FEC-9B84C83B63D9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Metadata", "Metadata\Metadata.csproj", "{961D11A0-44C8-48CD-BEEE-A6E6903AE58F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Not-Copy-Copy", "Not-Copy-Copy\Not-Copy-Copy.csproj", "{BF81D265-36E3-4DCA-891B-A0D875C1E68A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PrepareForOld", "PrepareForOld\PrepareForOld.csproj", "{F73F9468-0139-4B05-99CE-C6C0403D03E5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Property", "Property\Property.csproj", "{964B969A-719C-48AF-86C0-F97AF1397347}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Property-Compare", "Property-Compare\Property-Compare.csproj", "{692AA058-F142-44B0-88BC-F22AB5BE5EDF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Resize", "Resize\Resize.csproj", "{27D0D869-394D-4B07-83DF-2095B16026FC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Instance", "Instance\Instance.csproj", "{75D4A1EA-3727-4E28-9E87-FC1C77164ECD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1D231660-33B4-4763-9C9F-C6ACC8BA600D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1D231660-33B4-4763-9C9F-C6ACC8BA600D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1D231660-33B4-4763-9C9F-C6ACC8BA600D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1D231660-33B4-4763-9C9F-C6ACC8BA600D}.Release|Any CPU.Build.0 = Release|Any CPU + {372BFEDC-8E9C-4DDE-AD8D-66D9CE0670E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {372BFEDC-8E9C-4DDE-AD8D-66D9CE0670E1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {372BFEDC-8E9C-4DDE-AD8D-66D9CE0670E1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {372BFEDC-8E9C-4DDE-AD8D-66D9CE0670E1}.Release|Any CPU.Build.0 = Release|Any CPU + {DFEDB5F9-AFFC-40A2-9FEC-9B84C83B63D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DFEDB5F9-AFFC-40A2-9FEC-9B84C83B63D9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DFEDB5F9-AFFC-40A2-9FEC-9B84C83B63D9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DFEDB5F9-AFFC-40A2-9FEC-9B84C83B63D9}.Release|Any CPU.Build.0 = Release|Any CPU + {961D11A0-44C8-48CD-BEEE-A6E6903AE58F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {961D11A0-44C8-48CD-BEEE-A6E6903AE58F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {961D11A0-44C8-48CD-BEEE-A6E6903AE58F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {961D11A0-44C8-48CD-BEEE-A6E6903AE58F}.Release|Any CPU.Build.0 = Release|Any CPU + {BF81D265-36E3-4DCA-891B-A0D875C1E68A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BF81D265-36E3-4DCA-891B-A0D875C1E68A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BF81D265-36E3-4DCA-891B-A0D875C1E68A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BF81D265-36E3-4DCA-891B-A0D875C1E68A}.Release|Any CPU.Build.0 = Release|Any CPU + {F73F9468-0139-4B05-99CE-C6C0403D03E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F73F9468-0139-4B05-99CE-C6C0403D03E5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F73F9468-0139-4B05-99CE-C6C0403D03E5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F73F9468-0139-4B05-99CE-C6C0403D03E5}.Release|Any CPU.Build.0 = Release|Any CPU + {964B969A-719C-48AF-86C0-F97AF1397347}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {964B969A-719C-48AF-86C0-F97AF1397347}.Debug|Any CPU.Build.0 = Debug|Any CPU + {964B969A-719C-48AF-86C0-F97AF1397347}.Release|Any CPU.ActiveCfg = Release|Any CPU + {964B969A-719C-48AF-86C0-F97AF1397347}.Release|Any CPU.Build.0 = Release|Any CPU + {692AA058-F142-44B0-88BC-F22AB5BE5EDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {692AA058-F142-44B0-88BC-F22AB5BE5EDF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {692AA058-F142-44B0-88BC-F22AB5BE5EDF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {692AA058-F142-44B0-88BC-F22AB5BE5EDF}.Release|Any CPU.Build.0 = Release|Any CPU + {27D0D869-394D-4B07-83DF-2095B16026FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {27D0D869-394D-4B07-83DF-2095B16026FC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {27D0D869-394D-4B07-83DF-2095B16026FC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {27D0D869-394D-4B07-83DF-2095B16026FC}.Release|Any CPU.Build.0 = Release|Any CPU + {75D4A1EA-3727-4E28-9E87-FC1C77164ECD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {75D4A1EA-3727-4E28-9E87-FC1C77164ECD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {75D4A1EA-3727-4E28-9E87-FC1C77164ECD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {75D4A1EA-3727-4E28-9E87-FC1C77164ECD}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/package.json b/package.json new file mode 100644 index 0000000..24d3946 --- /dev/null +++ b/package.json @@ -0,0 +1,17 @@ +{ + "scripts": { + "Alpha": "ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "build": "dotnet build --runtime win-x64 --self-contained", + "dotnet-format": "dotnet format --report .vscode --verbosity detailed --severity warn View-by-Distance.sln", + "pull": "git pull", + "garbage-collect": "git gc", + "A-Instance-Pictures": "set ASPNETCORE_ENVIRONMENT=Development&& dotnet run --project \"Instance\\Instance.csproj\" --runtime win-x64 --no-self-contained \"C:\\Tmp\\phares\\Pictures\" s", + "B-Instance-Images--": "dotnet run --project \"Instance\\Instance.csproj\" --runtime win-x64 --no-self-contained \"D:\\Images\" s", + "A-Shared-Build": "dotnet build \"Shared\\View-by-Distance.Shared.csproj\" --runtime win-x64 --no-self-contained", + "Z-Compare-Build---": "dotnet build \"Compare\\Compare.csproj\" --runtime win-x64 --no-self-contained", + "Z-Instance-Build---": "dotnet build \"Instance\\Instance.csproj\" --runtime win-x64 --no-self-contained", + "Z-Compare-Publish-": "dotnet publish \"Compare\\Compare.csproj\" --configuration Release --runtime win-x64 --verbosity normal --self-contained true -o \"D:\\net6.0\\View-by-Distance\\Compare\\\"", + "Z-Instance-Publish-": "dotnet publish \"Instance\\Instance.csproj\" --configuration Release --runtime win-x64 --verbosity normal --self-contained true -o \"D:\\net6.0\\View-by-Distance\\Instance\\\"", + "Z-Instance-CUDA-Publish-": "dotnet publish \"Instance\\Instance.csproj\" --configuration Release --runtime win-x64 --verbosity normal --self-contained true -o \"D:\\net6.0\\View-by-Distance\\Instance-CUDA\\\"" + } +} \ No newline at end of file