Removed CopyManualFiles
Updated Tests
This commit is contained in:
parent
9991d2bfac
commit
5582504c4b
@ -9,13 +9,21 @@ namespace View_by_Distance.BlurHash.Models;
|
||||
public class C2_BlurHasher : IBlurHasher
|
||||
{
|
||||
|
||||
private readonly Dictionary<string, string[]> _FileGroups;
|
||||
private readonly IPropertyConfiguration _PropertyConfiguration;
|
||||
private readonly IReadOnlyDictionary<string, string[]> _FileGroups;
|
||||
|
||||
public C2_BlurHasher(IPropertyConfiguration propertyConfiguration, string? resultsFullGroupDirectory)
|
||||
public C2_BlurHasher(IPropertyConfiguration propertyConfiguration)
|
||||
{
|
||||
_FileGroups = new();
|
||||
_PropertyConfiguration = propertyConfiguration;
|
||||
_FileGroups = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(propertyConfiguration, resultsFullGroupDirectory, new string[] { propertyConfiguration.ResultContent, propertyConfiguration.ResultSingleton });
|
||||
}
|
||||
|
||||
public void Update(string resultsFullGroupDirectory)
|
||||
{
|
||||
_FileGroups.Clear();
|
||||
Dictionary<string, string[]> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, resultsFullGroupDirectory, new string[] { _PropertyConfiguration.ResultContent, _PropertyConfiguration.ResultSingleton });
|
||||
foreach (KeyValuePair<string, string[]> keyValuePair in keyValuePairs)
|
||||
_FileGroups.Add(keyValuePair.Key, keyValuePair.Value);
|
||||
}
|
||||
|
||||
string IBlurHasher.Encode(FileHolder fileHolder)
|
||||
@ -34,6 +42,8 @@ public class C2_BlurHasher : IBlurHasher
|
||||
string IBlurHasher.GetFile(FileHolder fileHolder)
|
||||
{
|
||||
string result;
|
||||
if (_FileGroups.Count == 0)
|
||||
throw new Exception("Call Update first!");
|
||||
(_, int directoryIndex) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration.ResultAllInOneSubdirectoryLength, fileHolder.Name);
|
||||
result = Path.Combine(_FileGroups[_PropertyConfiguration.ResultSingleton][directoryIndex], $"{fileHolder.Name}.csv");
|
||||
return result;
|
||||
@ -42,6 +52,8 @@ public class C2_BlurHasher : IBlurHasher
|
||||
string IBlurHasher.EncodeAndSave(FileHolder fileHolder)
|
||||
{
|
||||
string result;
|
||||
if (_FileGroups.Count == 0)
|
||||
throw new Exception("Call Update first!");
|
||||
int actualByte;
|
||||
string extension = ".png";
|
||||
IBlurHasher blurHasher = this;
|
||||
|
@ -24,14 +24,13 @@ namespace View_by_Distance.Instance;
|
||||
public partial class DlibDotNet
|
||||
{
|
||||
|
||||
private IBlurHasher? _BlurHasher;
|
||||
|
||||
private readonly D_Face _Faces;
|
||||
private readonly C_Resize _Resize;
|
||||
private readonly F_Random _Random;
|
||||
private readonly IConsole _Console;
|
||||
private readonly E_Distance _Distance;
|
||||
private readonly Serilog.ILogger? _Log;
|
||||
private readonly IBlurHasher _BlurHasher;
|
||||
private readonly D2_FaceParts _FaceParts;
|
||||
private readonly AppSettings _AppSettings;
|
||||
private readonly List<string> _Exceptions;
|
||||
@ -52,7 +51,6 @@ public partial class DlibDotNet
|
||||
IConsole console)
|
||||
{
|
||||
string message;
|
||||
_BlurHasher = null;
|
||||
_Console = console;
|
||||
_AppSettings = appSettings;
|
||||
_IsEnvironment = isEnvironment;
|
||||
@ -73,6 +71,7 @@ public partial class DlibDotNet
|
||||
_Random = new(configuration);
|
||||
if (configuration.IgnoreExtensions is null)
|
||||
throw new NullReferenceException(nameof(configuration.IgnoreExtensions));
|
||||
_BlurHasher = new BlurHash.Models.C2_BlurHasher(configuration.PropertyConfiguration);
|
||||
string propertyRoot = Property.Models.Stateless.IResult.GetResultsGroupDirectory(propertyConfiguration, nameof(A_Property), create: false);
|
||||
_PropertyRootExistedBefore = !Directory.Exists(propertyRoot);
|
||||
string argZero = args.Count > 0 ? Path.GetFullPath(args[0]) : Path.GetFullPath(propertyConfiguration.RootDirectory);
|
||||
@ -473,7 +472,7 @@ public partial class DlibDotNet
|
||||
LogNameWithoutExtensionIsIdFormatBut(item);
|
||||
if (nameWithoutExtensionIsPaddedIdFormat && item.ImageFileHolder.NameWithoutExtension.EndsWith(item.Property.Id.Value.ToString()[1..]))
|
||||
LogNameWithoutExtensionIsIdFormatBut(item);
|
||||
if (_BlurHasher is not null && resizedFileHolder.Exists && item.Property.Width is not null && item.Property.Width.Value > 4 && _Configuration.SaveBlurHashForOutputResolutions.Contains(outputResolution))
|
||||
if (resizedFileHolder.Exists && item.Property.Width is not null && item.Property.Width.Value > 4 && _Configuration.SaveBlurHashForOutputResolutions.Contains(outputResolution))
|
||||
{
|
||||
string? file = _BlurHasher.GetFile(resizedFileHolder);
|
||||
if (file is not null && !File.Exists(file))
|
||||
@ -716,7 +715,7 @@ public partial class DlibDotNet
|
||||
_Faces.Update(dResultsFullGroupDirectory);
|
||||
_Resize.Update(cResultsFullGroupDirectory);
|
||||
_FaceParts.Update(d2ResultsFullGroupDirectory);
|
||||
_BlurHasher = new BlurHash.Models.C2_BlurHasher(_Configuration.PropertyConfiguration, c2ResultsFullGroupDirectory);
|
||||
_BlurHasher.Update(c2ResultsFullGroupDirectory);
|
||||
for (int i = 0; i < containers.Length; i++)
|
||||
{
|
||||
container = containers[i];
|
||||
@ -849,7 +848,6 @@ public partial class DlibDotNet
|
||||
if (_Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution))
|
||||
mapLogic.SaveShortcutsForOutputResolutionsDuringMapLogic(containers, personKeyToIds, dFacesContentDirectory, distinctFilteredMappingCollection);
|
||||
ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> idToWholePercentagesToMapping = Map.Models.Stateless.Methods.IMapLogic.GetIdToWholePercentagesToFace(distinctFilteredMappingCollection);
|
||||
mapLogic.CopyManualFiles(dFacesContentDirectory, idToWholePercentagesToMapping);
|
||||
if (_Configuration.SaveMappedForOutputResolutions.Contains(outputResolution))
|
||||
mapLogic.SaveMapped(dFacesContentDirectory, d2FacePartsContentDirectory, d2FacePartsContentCollectionDirectory, personKeyToIds, distinctFilteredMappingCollection, idToWholePercentagesToMapping);
|
||||
if (_Configuration.SaveFaceDistancesForOutputResolutions.Contains(outputResolution))
|
||||
|
@ -59,7 +59,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
Stateless.MapLogic.SetSkipCollections(configuration, personContainers, a2PeopleSingletonDirectory, skipCollection, skipNotSkipCollection);
|
||||
List<Stateless.MapLogic.Record> records = Stateless.MapLogic.SetPersonCollectionsAndGetRecords(configuration, ticks, personContainers, eDistanceContentDirectory);
|
||||
ReadOnlyCollection<(Stateless.MapLogic.PersonKeyFormattedIdThenWholePercentages, PersonContainer)> readOnlyPossiblyNewPersonDisplayDirectoryNamesAndPersonContainer;
|
||||
locationContainers.AddRange(Stateless.MapLogic.GetLocationContainers(distance, maxDegreeOfParallelism, configuration, ticks, personContainers, eDistanceContentDirectory, skipCollection, records));
|
||||
locationContainers.AddRange(Stateless.MapLogic.GetLocationContainers(distance, maxDegreeOfParallelism, configuration, ticks, personContainers, eDistanceContentDirectory, eDistanceContentTicksDirectory, skipCollection, records));
|
||||
int lossCount = records.Count - locationContainers.Count;
|
||||
ReadOnlyCollection<Stateless.MapLogic.PersonKeyFormattedIdThenWholePercentages> personKeyFormattedIdThenWholePercentagesCollection = Stateless.MapLogic.GetPersonKeyFormattedIdThenWholePercentages(configuration, ticks, records);
|
||||
int unableToMatchCount = records.Count - personKeyFormattedIdThenWholePercentagesCollection.Count;
|
||||
@ -720,104 +720,6 @@ public class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
return result;
|
||||
}
|
||||
|
||||
public void CopyManualFiles(string dFacesContentDirectory, ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> idToWholePercentagesToMapping)
|
||||
{
|
||||
if (_Configuration is null)
|
||||
throw new NullReferenceException(nameof(_Configuration));
|
||||
int? id;
|
||||
string faceFile;
|
||||
Mapping? mapping;
|
||||
string checkFile;
|
||||
string directory;
|
||||
FileInfo fileInfo;
|
||||
const int zero = 0;
|
||||
string faceFileName;
|
||||
string shortcutFile;
|
||||
string facesDirectory;
|
||||
int? wholePercentages;
|
||||
string? directoryName;
|
||||
string mappingSegmentB;
|
||||
string personDirectory;
|
||||
string personKeyFormatted;
|
||||
string personDisplayFileName;
|
||||
PersonBirthday personBirthday;
|
||||
string? personDisplayDirectory;
|
||||
WindowsShortcut windowsShortcut;
|
||||
ReadOnlyDictionary<int, Mapping>? wholePercentagesToMapping;
|
||||
string by = nameof(Shared.Models.Stateless.IMapLogic.ManualCopy);
|
||||
ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPeronContainerCollection;
|
||||
string successful = $"_ {nameof(Shared.Models.Stateless.IMapLogic.ManualCopy).Humanize(LetterCasing.Title)} Successful";
|
||||
foreach (KeyValuePair<long, PersonContainer> personKeyToPersonContainer in _PersonKeyToPersonContainer)
|
||||
{
|
||||
if (personKeyToPersonContainer.Value.Key is null || personKeyToPersonContainer.Value.Birthdays is null || personKeyToPersonContainer.Value.Birthdays.Length == 0 || personKeyToPersonContainer.Value.PersonDirectory is null)
|
||||
continue;
|
||||
personBirthday = personKeyToPersonContainer.Value.Birthdays[zero];
|
||||
foreach (string personDisplayDirectoryAllFile in personKeyToPersonContainer.Value.DisplayDirectoryAllFiles)
|
||||
{
|
||||
if (!personDisplayDirectoryAllFile.EndsWith(_Configuration.FacesFileNameExtension))
|
||||
continue;
|
||||
(id, wholePercentages) = IMapping.GetConverted(_Configuration.FacesFileNameExtension, personDisplayDirectoryAllFile);
|
||||
if (id is null || wholePercentages is null)
|
||||
continue;
|
||||
fileInfo = new(personDisplayDirectoryAllFile);
|
||||
if (!fileInfo.Exists)
|
||||
continue;
|
||||
personDisplayFileName = Path.GetFileName(personDisplayDirectoryAllFile);
|
||||
personDisplayDirectory = Path.GetDirectoryName(personDisplayDirectoryAllFile);
|
||||
personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, personBirthday);
|
||||
mappingSegmentB = Stateless.MapLogic.GetMappingSegmentB(_Ticks, personBirthday, personKeyToPersonContainer.Value.ApproximateYears, fileInfo.CreationTime, isWrongYear: null);
|
||||
directory = Path.Combine(_EDistanceContentTicksDirectory, by, personKeyFormatted, mappingSegmentB);
|
||||
personDirectory = Path.Combine(directory, personKeyToPersonContainer.Value.DisplayDirectoryName, "lnk");
|
||||
if (!idToWholePercentagesToMapping.TryGetValue(id.Value, out wholePercentagesToMapping))
|
||||
continue;
|
||||
if (!wholePercentagesToMapping.TryGetValue(wholePercentages.Value, out mapping))
|
||||
continue;
|
||||
if (mapping.MappingFromLocation is null)
|
||||
continue;
|
||||
if (string.IsNullOrEmpty(personDisplayDirectory))
|
||||
throw new NotSupportedException();
|
||||
directoryName = Path.GetDirectoryName(mapping.MappingFromItem.RelativePath);
|
||||
if (string.IsNullOrEmpty(directoryName))
|
||||
throw new NotSupportedException();
|
||||
shortcutFile = Path.Combine(personDisplayDirectory, $"{personDisplayFileName}.lnk");
|
||||
facesDirectory = Stateless.MapLogic.GetFacesDirectory(_PropertyConfiguration, dFacesContentDirectory, mapping.MappingFromItem);
|
||||
faceFileName = $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_Configuration.FacesFileNameExtension}";
|
||||
checkFile = Path.Combine(directory, fileInfo.Name);
|
||||
if (!_IdThenWholePercentagesToPersonContainers.TryGetValue(id.Value, out wholePercentagesToPeronContainerCollection) || !wholePercentagesToPeronContainerCollection.ContainsKey(wholePercentages.Value))
|
||||
{
|
||||
if (!Directory.Exists(personDirectory))
|
||||
_ = Directory.CreateDirectory(personDirectory);
|
||||
if (!File.Exists(checkFile))
|
||||
File.Copy(personDisplayDirectoryAllFile, checkFile);
|
||||
}
|
||||
if (personDisplayDirectoryAllFile.Contains(successful))
|
||||
continue;
|
||||
directoryName = Path.Combine(personDisplayDirectory, successful);
|
||||
if (!Directory.Exists(directoryName))
|
||||
_ = Directory.CreateDirectory(directoryName);
|
||||
checkFile = Path.Combine(directoryName, personDisplayFileName);
|
||||
if (File.Exists(checkFile))
|
||||
File.Delete(personDisplayDirectoryAllFile);
|
||||
else
|
||||
File.Move(personDisplayDirectoryAllFile, checkFile);
|
||||
faceFile = Path.Combine(facesDirectory, faceFileName);
|
||||
if (!File.Exists(faceFile))
|
||||
continue;
|
||||
if (File.Exists(shortcutFile))
|
||||
continue;
|
||||
if (personKeyToPersonContainer.Value.PersonDirectory.Char == ']')
|
||||
windowsShortcut = new() { Path = faceFile };
|
||||
else
|
||||
windowsShortcut = new() { Path = checkFile };
|
||||
windowsShortcut.Save(shortcutFile);
|
||||
windowsShortcut.Dispose();
|
||||
if (!File.Exists(shortcutFile))
|
||||
continue;
|
||||
File.SetLastWriteTime(shortcutFile, mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private (string, PersonBirthday?) GetPersonBirthday(string[] directoryNames)
|
||||
{
|
||||
if (_Configuration is null)
|
||||
|
@ -826,30 +826,57 @@ internal abstract class MapLogic
|
||||
return results;
|
||||
}
|
||||
|
||||
private static List<(long, int?, string)> GetDisplayDirectoryAllFiles(string fileNameExtension, ReadOnlyCollection<PersonContainer> personContainers)
|
||||
private static List<(long, int?, string)> GetDisplayDirectoryAllFiles(string fileNameExtension, string personBirthdayFormat, long ticks, string eDistanceContentTicksDirectory, ReadOnlyCollection<PersonContainer> personContainers)
|
||||
{
|
||||
List<(long, int?, string)> results = new();
|
||||
string fileName;
|
||||
string checkFile;
|
||||
string? directory;
|
||||
string dateDirectory;
|
||||
string directoryName;
|
||||
string checkDirectory;
|
||||
string personKeyFormatted;
|
||||
PersonBirthday personBirthday;
|
||||
List<string> distinct = new();
|
||||
DateTime dateTime = new(ticks);
|
||||
string by = nameof(Shared.Models.Stateless.IMapLogic.ManualCopy);
|
||||
foreach (PersonContainer personContainer in personContainers)
|
||||
{
|
||||
if (personContainer.Key is null)
|
||||
continue;
|
||||
foreach (string displayDirectoryAllFile in personContainer.DisplayDirectoryAllFiles)
|
||||
for (int i = personContainer.DisplayDirectoryAllFiles.Length - 1; i > -1; i--)
|
||||
{
|
||||
fileName = Path.GetFileName(displayDirectoryAllFile);
|
||||
if (!fileName.EndsWith(fileNameExtension))
|
||||
if (!personContainer.DisplayDirectoryAllFiles[i].EndsWith(fileNameExtension))
|
||||
continue;
|
||||
fileName = Path.GetFileName(personContainer.DisplayDirectoryAllFiles[i]);
|
||||
if (distinct.Contains(fileName))
|
||||
continue;
|
||||
distinct.Add(fileName);
|
||||
results.Add(new(personContainer.Key.Value, null, displayDirectoryAllFile));
|
||||
results.Add(new(personContainer.Key.Value, null, personContainer.DisplayDirectoryAllFiles[i]));
|
||||
directory = Path.GetDirectoryName(personContainer.DisplayDirectoryAllFiles[i]);
|
||||
if (string.IsNullOrEmpty(directory))
|
||||
continue;
|
||||
directoryName = Path.GetFileName(directory);
|
||||
if (directoryName != personContainer.DisplayDirectoryName)
|
||||
continue;
|
||||
personBirthday = IPersonBirthday.GetPersonBirthday(personContainer.Key.Value);
|
||||
personKeyFormatted = IPersonBirthday.GetFormatted(personBirthdayFormat, personBirthday);
|
||||
dateDirectory = Path.Combine(eDistanceContentTicksDirectory, by, personKeyFormatted, dateTime.ToString("yyyy"));
|
||||
checkDirectory = Path.Combine(dateDirectory, personContainer.DisplayDirectoryName);
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
checkFile = Path.Combine(dateDirectory, fileName);
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
File.Move(personContainer.DisplayDirectoryAllFiles[i], checkFile);
|
||||
results.RemoveAt(results.Count - 1);
|
||||
personContainer.DisplayDirectoryAllFiles[i] = string.Empty;
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static List<(long PersonKey, int? DirectoryNumber, string File)> GetCollection(Configuration configuration, ReadOnlyCollection<PersonContainer> personContainers, List<Record> records)
|
||||
private static List<(long PersonKey, int? DirectoryNumber, string File)> GetCollection(Configuration configuration, long ticks, string eDistanceContentTicksDirectory, ReadOnlyCollection<PersonContainer> personContainers, List<Record> records)
|
||||
{
|
||||
List<(long PersonKey, int? DirectoryNumber, string File)> results = new();
|
||||
string file;
|
||||
@ -857,7 +884,7 @@ internal abstract class MapLogic
|
||||
string fileName;
|
||||
List<string> distinct = new();
|
||||
PersonBirthday? personBirthday;
|
||||
results.AddRange(GetDisplayDirectoryAllFiles(configuration.FacesFileNameExtension, personContainers));
|
||||
results.AddRange(GetDisplayDirectoryAllFiles(configuration.FacesFileNameExtension, configuration.PersonBirthdayFormat, ticks, eDistanceContentTicksDirectory, personContainers));
|
||||
foreach (Record record in records)
|
||||
{
|
||||
personBirthday = IPersonBirthday.GetPersonBirthday(configuration.PersonBirthdayFormat, record.PersonKeyFormatted);
|
||||
@ -907,6 +934,8 @@ internal abstract class MapLogic
|
||||
fileMatches = (from l in wholePercentagesCollection where l.WholePercentages == wholePercentages select l.File).ToArray();
|
||||
foreach (string fileMatch in fileMatches)
|
||||
{
|
||||
if (string.IsNullOrEmpty(fileMatch) || !File.Exists(fileMatch))
|
||||
continue;
|
||||
if (!fileMatch.EndsWith(".dup") && !File.Exists($"{fileMatch}.dup"))
|
||||
File.Move(fileMatch, $"{fileMatch}.dup");
|
||||
}
|
||||
@ -992,10 +1021,10 @@ internal abstract class MapLogic
|
||||
}
|
||||
}
|
||||
|
||||
internal static List<LocationContainer<MetadataExtractor.Directory>> GetLocationContainers(Shared.Models.Methods.IDistance<MetadataExtractor.Directory> distance, int maxDegreeOfParallelism, Configuration configuration, long ticks, ReadOnlyCollection<PersonContainer> personContainers, string eDistanceContentDirectory, Dictionary<int, List<(string, int)>> skipCollection, List<Record> records)
|
||||
internal static List<LocationContainer<MetadataExtractor.Directory>> GetLocationContainers(Shared.Models.Methods.IDistance<MetadataExtractor.Directory> distance, int maxDegreeOfParallelism, Configuration configuration, long ticks, ReadOnlyCollection<PersonContainer> personContainers, string eDistanceContentDirectory, string eDistanceContentTicksDirectory, Dictionary<int, List<(string, int)>> skipCollection, List<Record> records)
|
||||
{
|
||||
List<LocationContainer<MetadataExtractor.Directory>> results = new();
|
||||
List<(long PersonKey, int? DirectoryNumber, string File)> collection = GetCollection(configuration, personContainers, records);
|
||||
List<(long PersonKey, int? DirectoryNumber, string File)> collection = GetCollection(configuration, ticks, eDistanceContentTicksDirectory, personContainers, records);
|
||||
if (collection.Count > 0 && (configuration.DistanceMoveUnableToMatch || configuration.DistanceRenameToMatch))
|
||||
{
|
||||
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
||||
|
@ -345,12 +345,12 @@ public class Rename
|
||||
ProgressBar progressBar;
|
||||
List<Record> records = new();
|
||||
const string fileSearchFilter = "*";
|
||||
int offset = IDirectory.GetOffset();
|
||||
const string directorySearchFilter = "*";
|
||||
List<string> distinctDirectories = new();
|
||||
B_Metadata metadata = new(_PropertyConfiguration);
|
||||
List<(FileHolder, string)> verifiedToDoCollection = new();
|
||||
List<(FileHolder, string, string)> toDoCollection = new();
|
||||
int offset = IDirectory.GetOffset();
|
||||
List<(FileHolder, string)> verifiedToDoCollection = new();
|
||||
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
||||
List<string[]> filesCollection = IDirectory.GetFilesCollection(_PropertyConfiguration.RootDirectory, directorySearchFilter, fileSearchFilter);
|
||||
int count = filesCollection.Select(l => l.Length).Sum();
|
||||
|
@ -419,19 +419,25 @@ public class C_Resize
|
||||
return results;
|
||||
}
|
||||
|
||||
public FileHolder GetResizedFileHolder(string cResultsFullGroupDirectory, Item item, bool outputResolutionHasNumber)
|
||||
private FileHolder GetResizedFileHolder(string cResultsFullGroupDirectory, Item item, bool outputResolutionHasNumber, string fileName)
|
||||
{
|
||||
FileHolder result;
|
||||
if (outputResolutionHasNumber)
|
||||
result = new(Path.Combine(AngleBracketCollection[0].Replace("<>", _PropertyConfiguration.ResultContent), Path.GetFileName(item.ImageFileHolder.FullName)));
|
||||
result = new(Path.Combine(AngleBracketCollection[0].Replace("<>", _PropertyConfiguration.ResultContent), fileName));
|
||||
else
|
||||
{
|
||||
(string directoryName, _) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration.ResultAllInOneSubdirectoryLength, item.ImageFileHolder.Name);
|
||||
result = new(Path.Combine(cResultsFullGroupDirectory, _PropertyConfiguration.ResultContent, _PropertyConfiguration.ResultAllInOne, directoryName, Path.GetFileName(item.ImageFileHolder.FullName)));
|
||||
result = new(Path.Combine(cResultsFullGroupDirectory, _PropertyConfiguration.ResultContent, _PropertyConfiguration.ResultAllInOne, directoryName, fileName));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public FileHolder GetResizedFileHolder(string cResultsFullGroupDirectory, Item item, bool outputResolutionHasNumber) =>
|
||||
GetResizedFileHolder(cResultsFullGroupDirectory, item, outputResolutionHasNumber, item.ImageFileHolder.Name);
|
||||
|
||||
public FileHolder GetResizedFileHolder(string cResultsFullGroupDirectory, Item item, bool outputResolutionHasNumber, int id) =>
|
||||
GetResizedFileHolder(cResultsFullGroupDirectory, item, outputResolutionHasNumber, $"{id}{item.ImageFileHolder.ExtensionLowered}");
|
||||
|
||||
public Dictionary<string, int[]> GetResizeKeyValuePairs(Configuration configuration, string cResultsFullGroupDirectory, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, List<KeyValuePair<string, string>> metadataCollection, Shared.Models.Property property, MappingFromItem mappingFromItem)
|
||||
{
|
||||
Dictionary<string, int[]>? results;
|
||||
|
@ -42,6 +42,7 @@ taskTemplate: '^+^_${overdue ? ''^R'' : ''''}${name}^: ${relations ? (''\n^-^/^g
|
||||
- [eof-error](tasks/eof-error.md)
|
||||
- [shrink-percent](tasks/shrink-percent.md)
|
||||
- [setup-photo-prism-again-in-wsl-docker](tasks/setup-photo-prism-again-in-wsl-docker.md)
|
||||
- [move-copy-manual-files-to-get-display-directory-all-files](tasks/move-copy-manual-files-to-get-display-directory-all-files.md)
|
||||
- [rename-files-to-padded-number-string](tasks/rename-files-to-padded-number-string.md)
|
||||
- [genealogical-data-communication-as-golden](tasks/genealogical-data-communication-as-golden.md)
|
||||
- [look-for-family-from-jlink-in-x-mapped](tasks/look-for-family-from-jlink-in-x-mapped.md)
|
||||
|
@ -0,0 +1,11 @@
|
||||
---
|
||||
created: 2023-08-08T00:50:02.553Z
|
||||
updated: 2023-08-08T05:01:29.188Z
|
||||
assigned: ""
|
||||
progress: 0
|
||||
tags: []
|
||||
started: 2023-08-07T00:00:00.000Z
|
||||
completed: 2023-08-08T05:01:29.188Z
|
||||
---
|
||||
|
||||
# Move CopyManualFiles to GetDisplayDirectoryAllFiles
|
2
Shared/.vscode/tasks.json
vendored
2
Shared/.vscode/tasks.json
vendored
@ -34,7 +34,7 @@
|
||||
{
|
||||
"label": "File-Folder-Helper AOT s G File System to Genealogical Data Communication",
|
||||
"type": "shell",
|
||||
"command": "& L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net7.0/win-x64/publish/File-Folder-Helper.exe s F 'D:/1-Images-A/Images-dd514b88-Results/A2) People/dd514b88/([])/File-Folder-Helper/638268289384407819' -d 'D:/1-Images-A/Images-dd514b88-Results/A2) People/dd514b88/{2}'",
|
||||
"command": "& L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net7.0/win-x64/publish/File-Folder-Helper.exe s G 'D:/1-Images-A/Images-dd514b88-Results/A2) People/dd514b88/([])/File-Folder-Helper/638268289384407819' -d 'D:/1-Images-A/Images-dd514b88-Results/A2) People/dd514b88/{2}'",
|
||||
"problemMatcher": []
|
||||
}
|
||||
]
|
||||
|
@ -6,5 +6,6 @@ public interface IBlurHasher
|
||||
string Encode(FileHolder fileHolder);
|
||||
string GetFile(FileHolder fileHolder);
|
||||
string EncodeAndSave(FileHolder fileHolder);
|
||||
void Update(string resultsFullGroupDirectory);
|
||||
|
||||
}
|
@ -79,9 +79,19 @@ public interface IDirectory
|
||||
static (string[], List<(Models.FileHolder, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, List<string[]> filesCollection, string[] directories, Action? tick) =>
|
||||
XDirectory.GetToDoCollection(propertyConfiguration, copyDuplicates, ifCanUseId, filesCollection, directories, tick);
|
||||
|
||||
void TestStatic_CopyOrMove(List<(Models.FileHolder, string)> toDoCollection, bool move, bool moveBack, Action? tick) =>
|
||||
List<string> TestStatic_CopyOrMove(List<(Models.FileHolder, string)> toDoCollection, bool move, bool moveBack, Action? tick) =>
|
||||
CopyOrMove(toDoCollection, move, moveBack, tick);
|
||||
static List<string> CopyOrMove(List<(Models.FileHolder, string)> toDoCollection, bool move, bool moveBack, Action? tick) =>
|
||||
XDirectory.CopyOrMove(toDoCollection, move, moveBack, tick);
|
||||
|
||||
(bool, int?) TestStatic_GetId(int sortOrderOnlyLengthIndex, Models.FileHolder fileHolder) =>
|
||||
GetId(sortOrderOnlyLengthIndex, fileHolder);
|
||||
static (bool, int?) GetId(int sortOrderOnlyLengthIndex, Models.FileHolder fileHolder) =>
|
||||
XDirectory.GetId(sortOrderOnlyLengthIndex, fileHolder);
|
||||
|
||||
(bool, int?) TestStatic_GetId(Models.FileHolder fileHolder) =>
|
||||
GetId(fileHolder);
|
||||
static (bool, int?) GetId(Models.FileHolder fileHolder) =>
|
||||
XDirectory.GetId(GetSortOrderOnlyLengthIndex(), fileHolder);
|
||||
|
||||
}
|
@ -280,55 +280,57 @@ internal abstract partial class XDirectory
|
||||
}
|
||||
}
|
||||
|
||||
private static SortedRecord[] GetSortedRecords(List<string[]> filesCollection)
|
||||
internal static (bool, int?) GetId(int sortOrderOnlyLengthIndex, Models.FileHolder fileHolder)
|
||||
{
|
||||
List<SortedRecord> results = new();
|
||||
int? id;
|
||||
short? multiplier;
|
||||
char negativeMarker;
|
||||
int absoluteValueOfId;
|
||||
bool nameWithoutExtensionIsIdFormat = IProperty.NameWithoutExtensionIsIdFormat(fileHolder);
|
||||
bool nameWithoutExtensionIsPaddedIdFormat = IDirectory.NameWithoutExtensionIsPaddedIdFormat(fileHolder, sortOrderOnlyLengthIndex);
|
||||
if (!nameWithoutExtensionIsIdFormat && !nameWithoutExtensionIsPaddedIdFormat)
|
||||
id = null;
|
||||
else if (nameWithoutExtensionIsIdFormat)
|
||||
{
|
||||
if (!int.TryParse(fileHolder.NameWithoutExtension, out absoluteValueOfId))
|
||||
id = null;
|
||||
else
|
||||
id = absoluteValueOfId;
|
||||
}
|
||||
else
|
||||
{
|
||||
negativeMarker = fileHolder.NameWithoutExtension[sortOrderOnlyLengthIndex - 2];
|
||||
if (negativeMarker == '7')
|
||||
multiplier = 1;
|
||||
else if (negativeMarker == '3')
|
||||
multiplier = -1;
|
||||
else
|
||||
multiplier = null;
|
||||
if (!int.TryParse(fileHolder.NameWithoutExtension[sortOrderOnlyLengthIndex..], out absoluteValueOfId))
|
||||
id = null;
|
||||
else
|
||||
{
|
||||
id = absoluteValueOfId * multiplier;
|
||||
if (id is null || !fileHolder.NameWithoutExtension.EndsWith(id.Value.ToString()[1..]))
|
||||
id = null;
|
||||
}
|
||||
}
|
||||
return (nameWithoutExtensionIsIdFormat, id);
|
||||
}
|
||||
|
||||
private static SortedRecord[] GetSortedRecords(List<string[]> filesCollection)
|
||||
{
|
||||
List<SortedRecord> results = new();
|
||||
int? id;
|
||||
Models.FileHolder fileHolder;
|
||||
bool nameWithoutExtensionIsIdFormat;
|
||||
bool nameWithoutExtensionIsPaddedIdFormat;
|
||||
int sortOrderOnlyLengthIndex = IDirectory.GetSortOrderOnlyLengthIndex();
|
||||
foreach (string[] files in filesCollection)
|
||||
{
|
||||
foreach (string file in files)
|
||||
{
|
||||
fileHolder = new Models.FileHolder(file);
|
||||
nameWithoutExtensionIsIdFormat = IProperty.NameWithoutExtensionIsIdFormat(fileHolder);
|
||||
nameWithoutExtensionIsPaddedIdFormat = IDirectory.NameWithoutExtensionIsPaddedIdFormat(fileHolder, sortOrderOnlyLengthIndex);
|
||||
if (nameWithoutExtensionIsIdFormat)
|
||||
{
|
||||
multiplier = null;
|
||||
if (!int.TryParse(fileHolder.NameWithoutExtension, out absoluteValueOfId))
|
||||
id = null;
|
||||
else
|
||||
id = absoluteValueOfId;
|
||||
}
|
||||
else if (!nameWithoutExtensionIsPaddedIdFormat)
|
||||
{
|
||||
id = null;
|
||||
multiplier = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
negativeMarker = fileHolder.NameWithoutExtension[sortOrderOnlyLengthIndex - 2];
|
||||
if (negativeMarker == '7')
|
||||
multiplier = 1;
|
||||
else if (negativeMarker == '3')
|
||||
multiplier = -1;
|
||||
else
|
||||
multiplier = null;
|
||||
if (!int.TryParse(fileHolder.NameWithoutExtension[sortOrderOnlyLengthIndex..], out absoluteValueOfId))
|
||||
id = null;
|
||||
else
|
||||
{
|
||||
id = absoluteValueOfId * multiplier;
|
||||
if (id is null || !fileHolder.NameWithoutExtension.EndsWith(id.Value.ToString()[1..]))
|
||||
id = null;
|
||||
}
|
||||
}
|
||||
fileHolder = new(file);
|
||||
(nameWithoutExtensionIsIdFormat, id) = GetId(sortOrderOnlyLengthIndex, fileHolder);
|
||||
results.Add(new(fileHolder, nameWithoutExtensionIsIdFormat, id));
|
||||
}
|
||||
}
|
||||
|
@ -128,16 +128,14 @@ public class UnitTestResize
|
||||
[TestMethod]
|
||||
public void TestMethodResize()
|
||||
{
|
||||
string sourceFileName = "640794601.jpg";
|
||||
// string sourceFileName = "input.jpg";
|
||||
string sourceDirectoryName = "Halloween 2006";
|
||||
string sourceFileName = "100000507001158650387.jpg";
|
||||
string sourceDirectoryName = "Facebook/2023.2 Summer Facebook";
|
||||
Item item;
|
||||
bool reverse = false;
|
||||
FileHolder resizedFileHolder;
|
||||
List<string> parseExceptions = new();
|
||||
Shared.Models.Property? property = null;
|
||||
const bool isValidImageFormatExtension = true;
|
||||
Dictionary<string, int[]> outputResolutionToResize;
|
||||
List<Tuple<string, DateTime>> subFileTuples = new();
|
||||
List<KeyValuePair<string, string>> metadataCollection;
|
||||
int length = _PropertyConfiguration.RootDirectory.Length;
|
||||
@ -146,6 +144,7 @@ public class UnitTestResize
|
||||
bool outputResolutionHasNumber = outputResolution.Any(l => char.IsNumber(l));
|
||||
(string cResultsFullGroupDirectory, _, _) = GetResultsFullGroupDirectories(outputResolution);
|
||||
(string aResultsFullGroupDirectory, string bResultsFullGroupDirectory) = GetResultsFullGroupDirectories();
|
||||
Shared.Models.Methods.IBlurHasher blurHasher = new BlurHash.Models.C2_BlurHasher(_Configuration.PropertyConfiguration);
|
||||
_Logger.Information(_Configuration.ModelDirectory);
|
||||
A_Property propertyLogic = GetPropertyLogic(reverse, aResultsFullGroupDirectory);
|
||||
string aPropertySingletonDirectory = Path.Combine(aResultsFullGroupDirectory, "{}");
|
||||
@ -161,10 +160,15 @@ public class UnitTestResize
|
||||
FileHolder sourceDirectoryFileHolder = new(".json");
|
||||
string sourceDirectory = Path.GetFullPath(Path.Combine(_PropertyConfiguration.RootDirectory, sourceDirectoryName));
|
||||
FileHolder fileHolder = new(Path.Combine(sourceDirectory, sourceFileName));
|
||||
(_, int? id) = IDirectory.GetId(fileHolder);
|
||||
Assert.IsNotNull(id);
|
||||
string relativePath = IPath.GetRelativePath(fileHolder.FullName, length);
|
||||
string propertyLogicSourceDirectory = Path.GetFullPath(Path.Combine(aPropertySingletonDirectory, sourceDirectoryName));
|
||||
propertyLogic.SetAngleBracketCollection(aResultsFullGroupDirectory, propertyLogicSourceDirectory);
|
||||
resize.SetAngleBracketCollection(cResultsFullGroupDirectory, sourceDirectory);
|
||||
if (outputResolutionHasNumber)
|
||||
resize.SetAngleBracketCollection(cResultsFullGroupDirectory, sourceDirectory);
|
||||
resize.Update(cResultsFullGroupDirectory);
|
||||
blurHasher.Update(cResultsFullGroupDirectory);
|
||||
item = new(sourceDirectoryFileHolder, relativePath, fileHolder, isNotUniqueAndNeedsReview, isUniqueFileName, isValidImageFormatExtension, property, false, false, false);
|
||||
Assert.IsNotNull(item.ImageFileHolder);
|
||||
if (item.Property is null)
|
||||
@ -174,15 +178,15 @@ public class UnitTestResize
|
||||
}
|
||||
if (property is null || item.Property is null)
|
||||
throw new NullReferenceException(nameof(property));
|
||||
resizedFileHolder = resize.GetResizedFileHolder(cResultsFullGroupDirectory, item, outputResolutionHasNumber);
|
||||
Shared.Models.Methods.IBlurHasher blurHasher = new BlurHash.Models.C2_BlurHasher(_Configuration.PropertyConfiguration, resultsFullGroupDirectory: null);
|
||||
_ = blurHasher.Encode(resizedFileHolder);
|
||||
resizedFileHolder = resize.GetResizedFileHolder(cResultsFullGroupDirectory, item, outputResolutionHasNumber, id.Value);
|
||||
item.SetResizedFileHolder(resize.FileNameExtension, resizedFileHolder);
|
||||
MappingFromItem mappingFromItem = IMappingFromItem.GetMappingFromItem(item);
|
||||
(int _, metadataCollection) = metadata.GetMetadataCollection(subFileTuples, parseExceptions, changesFrom, mappingFromItem);
|
||||
outputResolutionToResize = resize.GetResizeKeyValuePairs(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, subFileTuples, parseExceptions, metadataCollection, item.Property, mappingFromItem);
|
||||
Dictionary<string, int[]> outputResolutionToResize = resize.GetResizeKeyValuePairs(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, subFileTuples, parseExceptions, metadataCollection, item.Property, mappingFromItem);
|
||||
Assert.IsNotNull(mappingFromItem.ResizedFileHolder);
|
||||
resize.SaveResizedSubfile(_Configuration.PropertyConfiguration, outputResolution, cResultsFullGroupDirectory, subFileTuples, item, item.Property, mappingFromItem, outputResolutionToResize);
|
||||
string blurHash = blurHasher.Encode(resizedFileHolder);
|
||||
Assert.IsNotNull(blurHash);
|
||||
NonThrowTryCatch();
|
||||
}
|
||||
|
||||
|
@ -41,11 +41,11 @@
|
||||
<PackageReference Include="Serilog" Version="2.12.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
||||
<ProjectReference Include="..\Property\Property.csproj" />
|
||||
<ProjectReference Include="..\Metadata\Metadata.csproj" />
|
||||
<ProjectReference Include="..\Resize\Resize.csproj" />
|
||||
<ProjectReference Include="..\BlurHash\BlurHash.csproj" />
|
||||
<ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" />
|
||||
<ProjectReference Include="..\Property-Compare\Property-Compare.csproj" />
|
||||
<ProjectReference Include="..\Metadata\Metadata.csproj" />
|
||||
<ProjectReference Include="..\Property\Property.csproj" />
|
||||
<ProjectReference Include="..\Resize\Resize.csproj" />
|
||||
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -203,15 +203,14 @@ public class UnitTestFace
|
||||
[TestMethod]
|
||||
public void TestMethodFace()
|
||||
{
|
||||
string sourceFileName = "640794601.jpg";
|
||||
string sourceDirectoryName = "Halloween 2006";
|
||||
string sourceFileName = "100000507001158650387.jpg";
|
||||
string sourceDirectoryName = "Facebook/2023.2 Summer Facebook";
|
||||
Item item;
|
||||
bool reverse = false;
|
||||
FileHolder resizedFileHolder;
|
||||
List<string> parseExceptions = new();
|
||||
Shared.Models.Property? property = null;
|
||||
const bool isValidImageFormatExtension = true;
|
||||
Dictionary<string, int[]> outputResolutionToResize;
|
||||
List<Tuple<string, DateTime>> subFileTuples = new();
|
||||
List<KeyValuePair<string, string>> metadataCollection;
|
||||
int length = _PropertyConfiguration.RootDirectory.Length;
|
||||
@ -220,6 +219,7 @@ public class UnitTestFace
|
||||
bool outputResolutionHasNumber = outputResolution.Any(l => char.IsNumber(l));
|
||||
(string cResultsFullGroupDirectory, _, _) = GetResultsFullGroupDirectories(outputResolution);
|
||||
(string aResultsFullGroupDirectory, string bResultsFullGroupDirectory) = GetResultsFullGroupDirectories();
|
||||
Shared.Models.Methods.IBlurHasher blurHasher = new BlurHash.Models.C2_BlurHasher(_Configuration.PropertyConfiguration);
|
||||
_Logger.Information(_Configuration.ModelDirectory);
|
||||
A_Property propertyLogic = GetPropertyLogic(reverse, aResultsFullGroupDirectory);
|
||||
string aPropertySingletonDirectory = Path.Combine(aResultsFullGroupDirectory, "{}");
|
||||
@ -235,10 +235,15 @@ public class UnitTestFace
|
||||
FileHolder sourceDirectoryFileHolder = new(".json");
|
||||
string sourceDirectory = Path.GetFullPath(Path.Combine(_PropertyConfiguration.RootDirectory, sourceDirectoryName));
|
||||
FileHolder fileHolder = new(Path.Combine(sourceDirectory, sourceFileName));
|
||||
(_, int? id) = IDirectory.GetId(fileHolder);
|
||||
Assert.IsNotNull(id);
|
||||
string relativePath = IPath.GetRelativePath(fileHolder.FullName, length);
|
||||
string propertyLogicSourceDirectory = Path.GetFullPath(Path.Combine(aPropertySingletonDirectory, sourceDirectoryName));
|
||||
propertyLogic.SetAngleBracketCollection(aResultsFullGroupDirectory, propertyLogicSourceDirectory);
|
||||
resize.SetAngleBracketCollection(cResultsFullGroupDirectory, sourceDirectory);
|
||||
if (outputResolutionHasNumber)
|
||||
resize.SetAngleBracketCollection(cResultsFullGroupDirectory, sourceDirectory);
|
||||
resize.Update(cResultsFullGroupDirectory);
|
||||
blurHasher.Update(cResultsFullGroupDirectory);
|
||||
item = new(sourceDirectoryFileHolder, relativePath, fileHolder, isNotUniqueAndNeedsReview, isUniqueFileName, isValidImageFormatExtension, property, false, false, false);
|
||||
Assert.IsNotNull(item.ImageFileHolder);
|
||||
if (item.Property is null)
|
||||
@ -248,23 +253,25 @@ public class UnitTestFace
|
||||
}
|
||||
if (property is null || item.Property is null)
|
||||
throw new NullReferenceException(nameof(property));
|
||||
resizedFileHolder = resize.GetResizedFileHolder(cResultsFullGroupDirectory, item, outputResolutionHasNumber);
|
||||
resizedFileHolder = resize.GetResizedFileHolder(cResultsFullGroupDirectory, item, outputResolutionHasNumber, id.Value);
|
||||
item.SetResizedFileHolder(resize.FileNameExtension, resizedFileHolder);
|
||||
MappingFromItem mappingFromItem = IMappingFromItem.GetMappingFromItem(item);
|
||||
(int _, metadataCollection) = metadata.GetMetadataCollection(subFileTuples, parseExceptions, changesFrom, mappingFromItem);
|
||||
outputResolutionToResize = resize.GetResizeKeyValuePairs(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, subFileTuples, parseExceptions, metadataCollection, item.Property, mappingFromItem);
|
||||
Dictionary<string, int[]> outputResolutionToResize = resize.GetResizeKeyValuePairs(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, subFileTuples, parseExceptions, metadataCollection, item.Property, mappingFromItem);
|
||||
Assert.IsNotNull(mappingFromItem.ResizedFileHolder);
|
||||
resize.SaveResizedSubfile(_Configuration.PropertyConfiguration, outputResolution, cResultsFullGroupDirectory, subFileTuples, item, item.Property, mappingFromItem, outputResolutionToResize);
|
||||
string blurHash = blurHasher.Encode(resizedFileHolder);
|
||||
Assert.IsNotNull(blurHash);
|
||||
Image image = FaceRecognition.LoadImageFile(mappingFromItem.ResizedFileHolder.FullName);
|
||||
Assert.IsNotNull(image);
|
||||
(Model model, PredictorModel predictorModel, ModelParameter modelParameter) = GetModel(_Configuration);
|
||||
FaceRecognition faceRecognition = new(_Configuration.NumberOfJitters, _Configuration.NumberOfTimesToUpsample, model, modelParameter, predictorModel);
|
||||
List<(Location Location, FaceRecognitionDotNet.FaceEncoding? FaceEncoding, Dictionary<FacePart, FacePoint[]>? FaceParts)> collection;
|
||||
collection = faceRecognition.GetCollection(image, locations: new(), includeFaceEncoding: true, includeFaceParts: true);
|
||||
Assert.IsTrue(collection.Count == 1);
|
||||
Assert.IsTrue(collection.Count == 2);
|
||||
List<FaceDistance> faceDistanceEncodings = (from l in collection where l.FaceEncoding is not null select new FaceDistance(l.FaceEncoding)).ToList();
|
||||
List<FaceDistance> faceDistanceLengths = FaceRecognition.FaceDistances(new(faceDistanceEncodings), faceDistanceEncodings[0]);
|
||||
Assert.IsTrue(faceDistanceLengths.Count == 1);
|
||||
Assert.IsTrue(faceDistanceLengths.Count == 2);
|
||||
Assert.IsNotNull(sourceFileName);
|
||||
NonThrowTryCatch();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user