From cd78555c3a54c0f229e0fa204e7295d924185376 Mon Sep 17 00:00:00 2001 From: reven Date: Thu, 23 Dec 2021 20:51:16 +1300 Subject: [PATCH] added InputDirectory, Zip node. Updated variables to use dotnotation --- BasicNodes/BasicNodes.csproj | Bin 2164 -> 2164 bytes BasicNodes/File/InputDirectory.cs | 31 ++++ BasicNodes/File/InputFile.cs | 19 +++ BasicNodes/Functions/Function.cs | 34 +++- BasicNodes/Tests/FileExtensionTests.cs | 2 +- BasicNodes/Tests/FileSizeTests.cs | 2 +- BasicNodes/Tests/FunctionTests.cs | 44 +++++- BasicNodes/Tests/PatternMatchTests.cs | 8 +- BasicNodes/Tests/PatternReplacerTests.cs | 4 +- BasicNodes/Tests/RenamerTests.cs | 12 +- BasicNodes/Tools/Zip.cs | 147 ++++++++++++++++++ FileFlows.Plugin.dll | Bin 29184 -> 30720 bytes FileFlows.Plugin.pdb | Bin 17964 -> 18264 bytes MetaNodes/MetaNodes.csproj | Bin 2208 -> 2208 bytes .../Tests/TheMovieDb/MovieLookupTests.cs | 18 +-- VideoNodes/InputNodes/VideoFile.cs | 14 +- VideoNodes/Tests/VideoInfoHelperTests.cs | 21 +-- VideoNodes/VideoNodes.csproj | Bin 2274 -> 2274 bytes VideoNodes/VideoNodes/VideoNode.cs | 24 +-- plugins.json | 6 +- ref/FileFlows.Plugin.dll | Bin 14336 -> 14336 bytes 21 files changed, 326 insertions(+), 60 deletions(-) create mode 100644 BasicNodes/File/InputDirectory.cs create mode 100644 BasicNodes/Tools/Zip.cs diff --git a/BasicNodes/BasicNodes.csproj b/BasicNodes/BasicNodes.csproj index 3ff9b45cccfc1daf78b076d38ecb83c083a58ffe..904fa216bd21af27c07bd71b0e63fdc8494d7b59 100644 GIT binary patch delta 24 dcmew&@I_$53r1!W27}438ACzzW@jctHUM#X2Xg=b delta 24 dcmew&@I_$53r1#R2Ghx}8ACzzW@jctHUM$O2YUbj diff --git a/BasicNodes/File/InputDirectory.cs b/BasicNodes/File/InputDirectory.cs new file mode 100644 index 00000000..7a07b7eb --- /dev/null +++ b/BasicNodes/File/InputDirectory.cs @@ -0,0 +1,31 @@ +namespace FileFlows.BasicNodes.File +{ + using System.ComponentModel; + using FileFlows.Plugin; + using FileFlows.Plugin.Attributes; + + public class InputDirectory: Node + { + public override int Outputs => 1; + public override FlowElementType Type => FlowElementType.Input; + public override string Icon => "far fa-folder"; + public override int Execute(NodeParameters args) + { + try + { + var info = new DirectoryInfo(args.WorkingFile); + if (info.Exists == false) + { + args.Logger?.ELog("Directory not found: " + args.WorkingFile); + return -1; + } + return 1; + } + catch (Exception ex) + { + args.Logger?.ELog("Failed in InputDirectory: " + ex.Message + Environment.NewLine + ex.StackTrace); + return -1; + } + } + } +} \ No newline at end of file diff --git a/BasicNodes/File/InputFile.cs b/BasicNodes/File/InputFile.cs index 0561cca9..c1b6597f 100644 --- a/BasicNodes/File/InputFile.cs +++ b/BasicNodes/File/InputFile.cs @@ -9,5 +9,24 @@ namespace FileFlows.BasicNodes.File public override int Outputs => 1; public override FlowElementType Type => FlowElementType.Input; public override string Icon => "far fa-file"; + + public override int Execute(NodeParameters args) + { + try + { + FileInfo fileInfo = new FileInfo(args.WorkingFile); + if (fileInfo.Exists == false) + { + args.Logger?.ELog("File not found: " + args.WorkingFile); + return -1; + } + return 1; + } + catch (Exception ex) + { + args.Logger?.ELog("Failed in InputFile: " + ex.Message + Environment.NewLine + ex.StackTrace); + return -1; + } + } } } \ No newline at end of file diff --git a/BasicNodes/Functions/Function.cs b/BasicNodes/Functions/Function.cs index d9f343c4..714e1c8d 100644 --- a/BasicNodes/Functions/Function.cs +++ b/BasicNodes/Functions/Function.cs @@ -8,6 +8,7 @@ namespace FileFlows.BasicNodes.Functions using Jint; using System.Text; using System.ComponentModel.DataAnnotations; + using System.Text.RegularExpressions; public class Function : Node { @@ -38,6 +39,14 @@ namespace FileFlows.BasicNodes.Functions if(fileInfo.Exists) fileSize = fileInfo.Length; + // replace Variables. with dictionary notation + string tcode = Code; + foreach (string k in args.Variables.Keys.OrderByDescending(x => x.Length)) + { + tcode = tcode.Replace("Variables." + k, "Variables['" + k + "']"); + } + + var sb = new StringBuilder(); var log = new { @@ -56,7 +65,7 @@ namespace FileFlows.BasicNodes.Functions try { - var result = int.Parse(engine.Evaluate(Code).ToObject().ToString()); + var result = int.Parse(engine.Evaluate(tcode).ToObject().ToString()); return result; } catch (Exception ex) @@ -65,5 +74,28 @@ namespace FileFlows.BasicNodes.Functions return -1; } } + + //private Dictionary ExplodeVariables(Dictionary input) + //{ + // Dictionary result = new(); + // foreach(var key in input.Keys) + // { + // if(key.IndexOf(".") > 0) + // { + // // folder.Date.Year + // // folder.Date.Month + // // folder.Date.Date + // //bk = Date + // string bk = key.Substring(0, key.IndexOf(".")); + // if(result.ContainsKey(bk) == false) + // result.Add(bk, new Dictionary()); + // Dictionary bkdict = (Dictionary)result[bk]; + // // nk = Year + // string nk = key.Substring(key.IndexOf(".") + 1); + // bkdict[] + // } + // } + // return result; + //} } } \ No newline at end of file diff --git a/BasicNodes/Tests/FileExtensionTests.cs b/BasicNodes/Tests/FileExtensionTests.cs index c7e1e7a2..b686808b 100644 --- a/BasicNodes/Tests/FileExtensionTests.cs +++ b/BasicNodes/Tests/FileExtensionTests.cs @@ -13,7 +13,7 @@ namespace BasicNodes.Tests [TestInitialize] public void TestStarting() { - Args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.mkv", new TestLogger());; + Args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.mkv", new TestLogger(), false, string.Empty); } diff --git a/BasicNodes/Tests/FileSizeTests.cs b/BasicNodes/Tests/FileSizeTests.cs index 58cd22fd..0abb7ca8 100644 --- a/BasicNodes/Tests/FileSizeTests.cs +++ b/BasicNodes/Tests/FileSizeTests.cs @@ -13,7 +13,7 @@ namespace BasicNodes.Tests [TestInitialize] public void TestStarting() { - Args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.mkv", new TestLogger()); + Args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.mkv", new TestLogger(), false, string.Empty); } diff --git a/BasicNodes/Tests/FunctionTests.cs b/BasicNodes/Tests/FunctionTests.cs index d938fb16..98d46781 100644 --- a/BasicNodes/Tests/FunctionTests.cs +++ b/BasicNodes/Tests/FunctionTests.cs @@ -13,7 +13,7 @@ namespace BasicNodes.Tests [TestInitialize] public void TestStarting() { - Args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.mkv", new TestLogger()); + Args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.mkv", new TestLogger(), false, string.Empty); } @@ -58,7 +58,7 @@ namespace BasicNodes.Tests { Function pm = new Function(); var logger = new TestLogger(); - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\sdfsdfdsvfdcxdsf.mkv", logger); + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\sdfsdfdsvfdcxdsf.mkv", logger, false, string.Empty); args.Variables = new Dictionary { { "miTitle", "Ghostbusters" }, @@ -75,7 +75,7 @@ return 0"; { Function pm = new Function(); var logger = new TestLogger(); - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\sdfsdfdsvfdcxdsf.mkv", logger); + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\sdfsdfdsvfdcxdsf.mkv", logger, false, string.Empty); args.Variables = new Dictionary { { "miTitle", "Ghostbusters" }, @@ -93,7 +93,7 @@ return 0"; { Function pm = new Function(); var logger = new TestLogger(); - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\sdfsdfdsvfdcxdsf.mkv", logger); + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\sdfsdfdsvfdcxdsf.mkv", logger, false, string.Empty); args.Variables = new Dictionary { { "miTitle", "Ghostbusters" }, @@ -111,7 +111,7 @@ return 0"; { Function pm = new Function(); var logger = new TestLogger(); - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\sdfsdfdsvfdcxdsf.mkv", logger); + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\sdfsdfdsvfdcxdsf.mkv", logger, false, string.Empty); args.Variables = new Dictionary { { "miTitle", "Ghostbusters" }, @@ -126,6 +126,40 @@ return 0"; Assert.AreEqual(1234d, args.Variables["NewItem"]); Assert.AreEqual(2001d, args.Variables["miYear"]); } + + + [TestMethod] + public void Function_UseVariables_Date() + { + Function pm = new Function(); + var logger = new TestLogger(); + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\sdfsdfdsvfdcxdsf.mkv", logger, false, string.Empty); + args.Variables = new Dictionary + { + { "folder.Date", new DateTime(2020, 03, 01) } + }; + pm.Code = @" +if(Variables.folder.Date.getFullYear() === 2020) return 1; +return 2"; + var result = pm.Execute(args); + Assert.AreEqual(1, result); + } + [TestMethod] + public void Function_UseVariables_MultipelDot() + { + Function pm = new Function(); + var logger = new TestLogger(); + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\sdfsdfdsvfdcxdsf.mkv", logger, false, string.Empty); + args.Variables = new Dictionary + { + { "folder.Date.Year", 2020 } + }; + pm.Code = @" +if(Variables.folder.Date.Year === 2020) return 1; +return 2"; + var result = pm.Execute(args); + Assert.AreEqual(1, result); + } } } diff --git a/BasicNodes/Tests/PatternMatchTests.cs b/BasicNodes/Tests/PatternMatchTests.cs index 3a207fab..55e6162a 100644 --- a/BasicNodes/Tests/PatternMatchTests.cs +++ b/BasicNodes/Tests/PatternMatchTests.cs @@ -13,7 +13,7 @@ namespace BasicNodes.Tests { PatternMatch pm = new PatternMatch(); pm.Pattern = @"\.mkv$"; - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.mkv", new TestLogger()); + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.mkv", new TestLogger(), false, string.Empty); args.SetWorkingFile($@"c:\temp\{Guid.NewGuid().ToString()}.mkv", dontDelete: true); var result = pm.Execute(args); @@ -25,7 +25,7 @@ namespace BasicNodes.Tests { PatternMatch pm = new PatternMatch(); pm.Pattern = @"\.mkv$"; - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.avi", new TestLogger()); + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.avi", new TestLogger(), false, string.Empty); args.SetWorkingFile($@"c:\temp\{Guid.NewGuid().ToString()}.avi", dontDelete: true); var result = pm.Execute(args); @@ -37,7 +37,7 @@ namespace BasicNodes.Tests { PatternMatch pm = new PatternMatch(); pm.Pattern = @"[-$"; - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.avi", new TestLogger()); + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.avi", new TestLogger(), false, string.Empty); args.SetWorkingFile($@"c:\temp\{Guid.NewGuid().ToString()}.avi", dontDelete: true); var result = pm.Execute(args); @@ -48,7 +48,7 @@ namespace BasicNodes.Tests { PatternMatch pm = new PatternMatch(); pm.Pattern = @"\-trailer"; - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile-TRAILER.avi", new TestLogger()); + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile-TRAILER.avi", new TestLogger(), false, string.Empty); args.SetWorkingFile($@"c:\temp\{Guid.NewGuid().ToString()}.avi", dontDelete: true); var result = pm.Execute(args); diff --git a/BasicNodes/Tests/PatternReplacerTests.cs b/BasicNodes/Tests/PatternReplacerTests.cs index 8de63484..ec6741b8 100644 --- a/BasicNodes/Tests/PatternReplacerTests.cs +++ b/BasicNodes/Tests/PatternReplacerTests.cs @@ -17,7 +17,7 @@ namespace BasicNodes.Tests new KeyValuePair("Seinfeld", "Batman") }; node.UnitTest = true; - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\Seinfeld.mkv", new TestLogger()); + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\Seinfeld.mkv", new TestLogger(), false, string.Empty); var result = node.Execute(args); Assert.AreEqual(1, result); @@ -34,7 +34,7 @@ namespace BasicNodes.Tests new KeyValuePair(@"0([1-9]+x[\d]+)", "$1"), }; node.UnitTest = true; - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\Seinfeld S03E06.mkv", new TestLogger()); + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\Seinfeld S03E06.mkv", new TestLogger(), false, string.Empty); var result = node.Execute(args); Assert.AreEqual(1, result); diff --git a/BasicNodes/Tests/RenamerTests.cs b/BasicNodes/Tests/RenamerTests.cs index ccf8779d..847b888b 100644 --- a/BasicNodes/Tests/RenamerTests.cs +++ b/BasicNodes/Tests/RenamerTests.cs @@ -12,7 +12,7 @@ namespace BasicNodes.Tests public void Renamer_Extension() { var logger = new TestLogger(); - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.mkv", logger); + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.mkv", logger, false, string.Empty); args.Variables = new Dictionary { { "miTitle", "Ghostbusters" }, @@ -36,7 +36,7 @@ namespace BasicNodes.Tests public void Renamer_Extension_DoubleDot() { var logger = new TestLogger(); - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.mkv", logger); + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.mkv", logger, false, string.Empty); args.Variables = new Dictionary { { "miTitle", "Ghostbusters" }, @@ -61,7 +61,7 @@ namespace BasicNodes.Tests public void Renamer_Empty_SquareBrackets() { var logger = new TestLogger(); - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.mkv", logger); + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.mkv", logger, false, string.Empty); args.Variables = new Dictionary { { "miTitle", "Ghostbusters" }, @@ -85,7 +85,7 @@ namespace BasicNodes.Tests public void Renamer_Empty_RoundBrackets() { var logger = new TestLogger(); - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.mkv", logger); + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.mkv", logger, false, string.Empty); args.Variables = new Dictionary { { "miTitle", "Ghostbusters" }, @@ -108,7 +108,7 @@ namespace BasicNodes.Tests public void Renamer_Empty_SquareBrackets_Extension() { var logger = new TestLogger(); - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.mkv", logger); + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.mkv", logger, false, string.Empty); args.Variables = new Dictionary { { "miTitle", "Ghostbusters" }, @@ -133,7 +133,7 @@ namespace BasicNodes.Tests public void Renamer_Colon() { var logger = new TestLogger(); - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.mkv", logger); + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.mkv", logger, false, string.Empty); args.Variables = new Dictionary { { "miTitle", "Batman Unlimited: Mech vs Mutants" }, diff --git a/BasicNodes/Tools/Zip.cs b/BasicNodes/Tools/Zip.cs new file mode 100644 index 00000000..f9e70d28 --- /dev/null +++ b/BasicNodes/Tools/Zip.cs @@ -0,0 +1,147 @@ +namespace FileFlows.BasicNodes.File +{ + using FileFlows.Plugin; + using FileFlows.Plugin.Attributes; + using System; + using System.ComponentModel.DataAnnotations; + using System.IO.Compression; + + + public class Zip : Node + { + public override int Inputs => 1; + public override int Outputs => 1; + public override FlowElementType Type => FlowElementType.Process; + public override string Icon => "fas fa-file-archive"; + private string _DestinationPath = string.Empty; + private string _DestinationFile = string.Empty; + + [Folder(1)] + public string DestinationPath + { + get => _DestinationPath; + set { _DestinationPath = value ?? ""; } + } + + [TextVariable(2)] + public string DestinationFile + { + get => _DestinationFile; + set { _DestinationFile = value ?? ""; } + } + + public override int Execute(NodeParameters args) + { + bool isDir = false; + + try + { + if (System.IO.Directory.Exists(args.WorkingFile)) + { + isDir = true; + } + else if (System.IO.File.Exists(args.WorkingFile) == false) + { + args.Logger?.ELog("File or folder does not exist: " + args.WorkingFile); + return -1; + } + + string destDir = DestinationPath; + if (string.IsNullOrEmpty(destDir)) + { + if (isDir) + destDir = new DirectoryInfo(args.LibraryPath).FullName; + else + destDir = new FileInfo(args.FileName)?.DirectoryName ?? String.Empty; + if (string.IsNullOrEmpty(destDir)) + { + args.Logger?.ELog("Failed to get destination directory"); + return -1; + } + } + else + { + // incase they set a linux path on windows or vice versa + destDir = destDir.Replace('\\', Path.DirectorySeparatorChar); + destDir = destDir.Replace('/', Path.DirectorySeparatorChar); + + destDir = args.ReplaceVariables(destDir, stripMissing: true); + + // this converts it to the actual OS path + destDir = new FileInfo(destDir).DirectoryName!; + args.CreateDirectoryIfNotExists(destDir); + } + + string destFile = args.ReplaceVariables(DestinationFile ?? string.Empty, true); + if (string.IsNullOrEmpty(destFile)) + { + if (isDir) + destFile = new DirectoryInfo(args.FileName).Name + ".zip"; + else + destFile = new FileInfo(args.FileName).Name + ".zip"; + } + if (destFile.ToLower().EndsWith(".zip") == false) + destFile += ".zip"; + destFile = Path.Combine(destDir, destFile); + + args.Logger?.ILog($"Compressing '{args.WorkingFile}' to '{destFile}'"); + if (isDir) + { + var dir = new DirectoryInfo(args.WorkingFile); + var files = dir.GetFiles("*.*", SearchOption.AllDirectories); + using (FileStream fs = new FileStream(destFile, FileMode.Create)) + { + using (ZipArchive arch = new ZipArchive(fs, ZipArchiveMode.Create)) + { + args?.PartPercentageUpdate(0); + float current= 0; + float count = files.Length; + foreach(var file in files) + { + ++count; + if (file.FullName.ToLower() == destFile.ToLower()) + continue; // cant zip the zip we are creating + string relative = file.FullName.Substring(dir.FullName.Length + 1); + try + { + arch.CreateEntryFromFile(file.FullName, relative, CompressionLevel.SmallestSize); + } + catch (Exception ex) + { + args.Logger?.WLog("Failed to add file to zip: " + file.FullName + " => " + ex.Message); + } + args?.PartPercentageUpdate((current / count) * 100); + } + args?.PartPercentageUpdate(100); + } + } + } + else + { + using (FileStream fs = new FileStream(destFile, FileMode.Create)) + { + using (ZipArchive arch = new ZipArchive(fs, ZipArchiveMode.Create)) + { + arch.CreateEntryFromFile(args.WorkingFile, new FileInfo(args.FileName).Name); + } + } + } + + if (System.IO.File.Exists(destFile)) + { + args.SetWorkingFile(destFile); + args.Logger?.ILog("Zip created at: " + destFile); + return 1; + } + + args.Logger?.ELog("Failed to create zip: " + destFile); + return -1; + } + catch (Exception ex) + { + args.Logger?.ELog("Failed creating zip: " + ex.Message + Environment.NewLine + ex.StackTrace); + return -1; + } + } + } +} diff --git a/FileFlows.Plugin.dll b/FileFlows.Plugin.dll index 0917a19dc95cc8c53247bb4275e93454e929d70a..ece315dd22e85d18b3d780db7d8d3b75ad1f6d08 100644 GIT binary patch literal 30720 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 X+h+iiG?ag9*?(IJ|Eu_aum}DNC%M?R literal 29184 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 delta 2801 zcmbuBX>3$g6vxkdv(wo+ODWLODO;z70-e4NQ=rp!N?TD-q=iZq3uP0E6p*DwaHjnL z6e^2PghYaIfuKbNn^c2K2w%_-LLfoV7!wzW1~3FQA<-EBXL=uA`_)PQ@15T{=broS z^6s1K`;=3?$^k9;my>Ah3q-%Wh)xsihD{q+uUqvTOnS>rWMH@Q*wPSKA4N`*W4omE^f%KV61?hVmx+ zX*$#heF)u!?nA4m_~|J0HdHm$Pgka*efk%qUiwG8@3 zbJ9)Cg-+dcPcufrcR&5D>5A$PQjluPf;1OuE*p$ojP_TVx2Q=AR)*Jri1$b-{ma9_ zn#7~9gk@l}$mi`71zQBq15cB<2pp66mS8*bx5KW1%9BVKCJL-!hhQJ!C} zG(+Nvcy4AF;@ybtfM$Z-BA?q=fIWhFE5;?hjP^-(c#*)P$%lhE6TAhSDcBD_2)hEl zO2h-A;3fE&gWwLtas+3A@eYzxa5ng5*fIF3kUv7S|6HMD+A&fT2qK9SMu`Fz!MWfU zMFF0+(V~D2Hov_F+hNyA%<(#jIbJWZ4gJ$Yl7kawOUwlxmYCy@;axR4%$VPc$2KbaPxB&JP!6C%iX5S*@=Zk#q?@1gu zV+`iA=PAf=@Q4>n%p-nUYLE$Tk(k>rf#mi}CFb_6QvNZC^RfSklb0c3tazev;N=pB z!7CCtNukDyf&;}EB3B<90*wZuGwYaTG>gEvUq0|(I@@LGxIgP)anlf+io%b<18 zI57a8!FGvx2G*m!5$74)U@))8FlZxWBya&fj11-i+^NAF-z+i5x1fp<4}!NE9l+-L z9TM}BbqePG(+S&f%oqhY;rSsAwh!SQ5_1P!$Y{??(1q97;0)!z{FR80CnZVO0lbF0 zu*)ZiDfEGN58)n(XIO{~=JTKnUsL7+w2!NNOcU+J1B6ArUnJ&Jk`FTem15BN@k^)B zQoY(WHn}!!_pzIb(snnlW}J!qTbRD);;PUATvd7vR}<~Q)j}t6CHg;6MgP&2*>VI` z6gq*cn!fUKvCZ{O>3|WFxzdEqvB{PQ!%;uD(TBB7MFD>?;iG|$?$TQot&y&rEIk`3xf+)xoi|x z$?3DI)NLar+!^KZxhTI`FN#mLj>H})+N!t2M~&`wxoL!I$6r8&a?JdFR5!F@%izQ1 zPwml<#G9>nx=__A?5-lz$wYkGNQn-%jkF7>DWPG!X7cKPrKlsbg>!QBI;{HG}Z1iTh-3EOYcim znGWZ<^k6Gw S{&eG8VxsI7dQN@0viBeE)+nF= diff --git a/MetaNodes/MetaNodes.csproj b/MetaNodes/MetaNodes.csproj index c1fe9c75fde8fed0f2bf3bcf14dd2bb1776df16e..0a85bcae57de3899d0bee5818bfe4c5c3b0a02a6 100644 GIT binary patch delta 24 dcmZ1=xIl2jEJkJ%27}3S8ACzz=C6#a*#KPB2V4LE delta 24 dcmZ1=xIl2jEJkKy2GhxN8ACzz=C6#a*#KQ22V?*M diff --git a/MetaNodes/Tests/TheMovieDb/MovieLookupTests.cs b/MetaNodes/Tests/TheMovieDb/MovieLookupTests.cs index 409b3a46..cceb49d6 100644 --- a/MetaNodes/Tests/TheMovieDb/MovieLookupTests.cs +++ b/MetaNodes/Tests/TheMovieDb/MovieLookupTests.cs @@ -12,7 +12,7 @@ namespace MetaNodes.Tests.TheMovieDb [TestMethod] public void MovieLookupTests_File_Ghostbusters() { - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\Ghostbusters 1984.mkv", new TestLogger()); + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\Ghostbusters 1984.mkv", new TestLogger(), false, string.Empty); MovieLookup ml = new MovieLookup(); ml.UseFolderName = false; @@ -31,7 +31,7 @@ namespace MetaNodes.Tests.TheMovieDb [TestMethod] public void MovieLookupTests_File_Ghostbusters2() { - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\Ghostbusters 2.mkv", new TestLogger()); + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\Ghostbusters 2.mkv", new TestLogger(), false, string.Empty); MovieLookup ml = new MovieLookup(); ml.UseFolderName = false; @@ -50,7 +50,7 @@ namespace MetaNodes.Tests.TheMovieDb [TestMethod] public void MovieLookupTests_File_WithDots() { - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\Back.To.The.Future.2.mkv", new TestLogger()); + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\Back.To.The.Future.2.mkv", new TestLogger(), false, string.Empty); MovieLookup ml = new MovieLookup(); ml.UseFolderName = false; @@ -69,7 +69,7 @@ namespace MetaNodes.Tests.TheMovieDb [TestMethod] public void MovieLookupTests_File_WithYear() { - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\Back.To.The.Future.1989.mkv", new TestLogger()); + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\Back.To.The.Future.1989.mkv", new TestLogger(), false, string.Empty); MovieLookup ml = new MovieLookup(); ml.UseFolderName = false; @@ -88,7 +88,7 @@ namespace MetaNodes.Tests.TheMovieDb [TestMethod] public void MovieLookupTests_Folder_WithYear() { - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\Back To The Future (1989)\Jaws.mkv", new TestLogger()); + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\Back To The Future (1989)\Jaws.mkv", new TestLogger(), false, string.Empty); MovieLookup ml = new MovieLookup(); ml.UseFolderName = true; @@ -107,7 +107,7 @@ namespace MetaNodes.Tests.TheMovieDb [TestMethod] public void MovieLookupTests_VariablesSet() { - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\Back To The Future (1989)\Jaws.mkv", new TestLogger()); + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\Back To The Future (1989)\Jaws.mkv", new TestLogger(), false, string.Empty); MovieLookup ml = new MovieLookup(); ml.UseFolderName = true; @@ -123,7 +123,7 @@ namespace MetaNodes.Tests.TheMovieDb [TestMethod] public void MovieLookupTests_NoMatchNoVariables() { - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\sdfsdfdsvfdcxdsf.mkv", new TestLogger()); + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\sdfsdfdsvfdcxdsf.mkv", new TestLogger(), false, string.Empty); MovieLookup ml = new MovieLookup(); ml.UseFolderName = false; @@ -138,7 +138,7 @@ namespace MetaNodes.Tests.TheMovieDb [TestMethod] public void MovieLookupTests_ComplexFile() { - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\Constantine.2005.German.DL.AC3.1080p.BluRay.x265-Fun{{fdg$ERGESDG32fesdfgds}}\Constantine.2005.German.DL.AC3.1080p.BluRay.x265-Fun{{fdg$ERGESDG32fesdfgds}}.mkv", new TestLogger()); + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\Constantine.2005.German.DL.AC3.1080p.BluRay.x265-Fun{{fdg$ERGESDG32fesdfgds}}\Constantine.2005.German.DL.AC3.1080p.BluRay.x265-Fun{{fdg$ERGESDG32fesdfgds}}.mkv", new TestLogger(), false, string.Empty); MovieLookup ml = new MovieLookup(); ml.UseFolderName = false; @@ -157,7 +157,7 @@ namespace MetaNodes.Tests.TheMovieDb [TestMethod] public void MovieLookupTests_WonderWoman() { - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\Wonder.Woman.1984.2020.German.DL.AC3.1080p.BluRay.x265-Fun{{fdg$ERGESDG32fesdfgds}}\Wonder.Woman.1984.2020.German.DL.AC3.1080p.BluRay.x265-Fun{{fdg$ERGESDG32fesdfgds}}.mkv", new TestLogger()); + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\Wonder.Woman.1984.2020.German.DL.AC3.1080p.BluRay.x265-Fun{{fdg$ERGESDG32fesdfgds}}\Wonder.Woman.1984.2020.German.DL.AC3.1080p.BluRay.x265-Fun{{fdg$ERGESDG32fesdfgds}}.mkv", new TestLogger(), false, string.Empty); MovieLookup ml = new MovieLookup(); ml.UseFolderName = false; diff --git a/VideoNodes/InputNodes/VideoFile.cs b/VideoNodes/InputNodes/VideoFile.cs index 3cafd2f7..e6d3e1b9 100644 --- a/VideoNodes/InputNodes/VideoFile.cs +++ b/VideoNodes/InputNodes/VideoFile.cs @@ -15,13 +15,13 @@ namespace FileFlows.VideoNodes { _Variables = new Dictionary() { - { "viVideoCodec", "hevc" }, - { "viAudioCodec", "ac3" }, - { "viAudioCodecs", "ac3,aac"}, - { "viAudioLanguage", "eng" }, - { "viAudioLanguages", "eng, mao" }, - { "viResolution", "1080p" }, - { "viDuration", 1800 }, + { "vi.Video.Codec", "hevc" }, + { "vi.Audio.Codec", "ac3" }, + { "vi.Audio.Codecs", "ac3,aac"}, + { "vi.Audio.Language", "eng" }, + { "vi.Audio.Languages", "eng, mao" }, + { "vi.Resolution", "1080p" }, + { "vi.Duration", 1800 }, }; } diff --git a/VideoNodes/Tests/VideoInfoHelperTests.cs b/VideoNodes/Tests/VideoInfoHelperTests.cs index 54ad2101..7907167e 100644 --- a/VideoNodes/Tests/VideoInfoHelperTests.cs +++ b/VideoNodes/Tests/VideoInfoHelperTests.cs @@ -33,7 +33,7 @@ namespace VideoNodes.Tests { "subrip", "srt" }; - var args = new FileFlows.Plugin.NodeParameters(file, new TestLogger()); + var args = new FileFlows.Plugin.NodeParameters(file, new TestLogger(), false, string.Empty); args.GetToolPath = (string tool) => @"C:\utils\ffmpeg\ffmpeg.exe"; args.TempPath = @"D:\videos\temp"; @@ -48,25 +48,28 @@ namespace VideoNodes.Tests [TestMethod] public void VideoInfoTest_DetectBlackBars() { - const string file = @"D:\videos\unprocessed\The Witcher - S02E05 - Turn Your Back.mkv"; - var vi = new VideoInfoHelper(@"C:\utils\ffmpeg\ffmpeg.exe", new TestLogger()); - vi.Read(@"D:\videos\unprocessed\Bourne.mkv"); + //const string file = @"D:\videos\unprocessed\The Witcher - S02E05 - Turn Your Back.mkv"; + //const string file = @"D:\videos\unprocessed\Hawkeye (2021) - S01E05 - Ronin.mkv"; + const string file = @"\\ORACLE\tv\Dexter - New Blood\Season 1\Dexter - New Blood - S01E07 - Skin of Her Teeth.mkv"; + //var vi = new VideoInfoHelper(@"C:\utils\ffmpeg\ffmpeg.exe", new TestLogger(), false, string.Empty); + //vi.Read(@"D:\videos\unprocessed\Bourne.mkv"); - var args = new FileFlows.Plugin.NodeParameters(file, new TestLogger()); + var args = new FileFlows.Plugin.NodeParameters(file, new TestLogger(), false, string.Empty); args.GetToolPath = (string tool) => @"C:\utils\ffmpeg\ffmpeg.exe"; args.TempPath = @"D:\videos\temp"; int result = new DetectBlackBars().Execute(args); Assert.IsTrue(result > 0); - } + + [TestMethod] public void VideoInfoTest_NvidiaCard() { const string file = @"D:\videos\unprocessed\Bourne.mkv"; const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var args = new FileFlows.Plugin.NodeParameters(file, new TestLogger()); + var args = new FileFlows.Plugin.NodeParameters(file, new TestLogger(), false, string.Empty); //args.Process = new FileFlows.Plugin.ProcessHelper(args.Logger); var node = new VideoEncode(); @@ -80,7 +83,7 @@ namespace VideoNodes.Tests { const string file = @"D:\videos\unprocessed\Bourne.mkv"; const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var args = new FileFlows.Plugin.NodeParameters(file, new TestLogger()); + var args = new FileFlows.Plugin.NodeParameters(file, new TestLogger(), false, string.Empty); //args.Process = new FileFlows.Plugin.ProcessHelper(args.Logger); var node = new VideoEncode(); @@ -94,7 +97,7 @@ namespace VideoNodes.Tests { const string file = @"D:\videos\unprocessed\Bourne.mkv"; const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var args = new FileFlows.Plugin.NodeParameters(file, new TestLogger()); + var args = new FileFlows.Plugin.NodeParameters(file, new TestLogger(), false, string.Empty); //args.Process = new FileFlows.Plugin.ProcessHelper(args.Logger); var node = new VideoEncode(); diff --git a/VideoNodes/VideoNodes.csproj b/VideoNodes/VideoNodes.csproj index c3102d87f183d7b2387be84a2e7557fb14899fcd..0f8a1e270caeb7d4af7aad651aefe0ba5506e8d4 100644 GIT binary patch delta 24 dcmaDP_(*WWJtk%o27}2DnL x.Codec).Where(x => string.IsNullOrEmpty(x) == false))); - Variables.AddOrUpdate("viAudioLanguages", string.Join(", ", videoInfo.AudioStreams.Select(x => x.Language).Where(x => string.IsNullOrEmpty(x) == false))); + Variables.AddOrUpdate("vi.Audio.Language", videoInfo.AudioStreams[0].Language); + Variables.AddOrUpdate("vi.Audio.Codecs", string.Join(", ", videoInfo.AudioStreams.Select(x => x.Codec).Where(x => string.IsNullOrEmpty(x) == false))); + Variables.AddOrUpdate("vi.Audio.Languages", string.Join(", ", videoInfo.AudioStreams.Select(x => x.Language).Where(x => string.IsNullOrEmpty(x) == false))); } if (videoInfo.VideoStreams[0].Width == 1920) - Variables.AddOrUpdate("viResolution", "1080"); + Variables.AddOrUpdate("vi.Resolution", "1080"); else if (videoInfo.VideoStreams[0].Width == 3840) - Variables.AddOrUpdate("viResolution", "4l"); + Variables.AddOrUpdate("vi.Resolution", "4l"); else if (videoInfo.VideoStreams[0].Width == 1280) - Variables.AddOrUpdate("viResolution", "720p"); + Variables.AddOrUpdate("vi.Resolution", "720p"); else if (videoInfo.VideoStreams[0].Width < 1280) - Variables.AddOrUpdate("viResolution", "SD"); + Variables.AddOrUpdate("vi.Resolution", "SD"); else - Variables.AddOrUpdate("viResolution", videoInfo.VideoStreams[0].Width + "x" + videoInfo.VideoStreams[0].Height); + Variables.AddOrUpdate("vi.Resolution", videoInfo.VideoStreams[0].Width + "x" + videoInfo.VideoStreams[0].Height); args.UpdateVariables(variables); } diff --git a/plugins.json b/plugins.json index 6fb22ad8..10f86b2a 100644 --- a/plugins.json +++ b/plugins.json @@ -1,17 +1,17 @@ [ { "Name": "BasicNodes", - "Version": "0.0.1.34", + "Version": "0.0.1.40", "Package": "https://github.com/revenz/FileFlowsPlugins/blob/master/Builds/BasicNodes.zip?raw=true" }, { "Name": "MetaNodes", - "Version": "0.0.1.34", + "Version": "0.0.1.40", "Package": "https://github.com/revenz/FileFlowsPlugins/blob/master/Builds/MetaNodes.zip?raw=true" }, { "Name": "VideoNodes", - "Version": "0.0.1.34", + "Version": "0.0.1.40", "Package": "https://github.com/revenz/FileFlowsPlugins/blob/master/Builds/VideoNodes.zip?raw=true" } ] diff --git a/ref/FileFlows.Plugin.dll b/ref/FileFlows.Plugin.dll index 3ad80cecb8b61a6ab1048ae613351766335db1aa..8dd6ea9362e02802fb2bd97b47786f34eb623c0f 100644 GIT binary patch literal 14336 zcmeHO3ve9OmA$WLG}AL94U%FL1F}7`j1j+yWE*3HZ6xc1Wo*e9H+Bk|72sfC;dK5E4j4dGk-mXQ_lub`uk_uHCIbsuq$WTbqr&`BWva$&!T4XP2<& z-u_HWHYA&^RBffwcAviI-uLc%@4ipJ?rH6~?rw?@Q55IPFB3h6D<55guMSn1)62h@ zrbiP`wmzn|KiN7mWtB5Cc4^W!rZYLCSS&f2aWi9AiW#ez=^Yx*OqcRzwxJ=p(sRAD zk7&D!(oOe%;!eM`6SN|eQXNDWL8H6c_w2*93ugu=QKMWnx8AJa`pa<)=#dDG-O5S% zf9>i~R^jM{-ys&NL?7iqEIj6j>Y-~#x|W5uSL0nl)g_eoE_le=W}$?H+$NgC z$>pxY89KU9ZixO_{1cAAJ@0t^ciZdVyX}F=!z-6e6hHVU+|)le?KBZM$m=Q&UYj(k zqmeG6XD%R8to#Fx%JabM%>K36j_jI_HJuySVI38KM_x*8i z$r$}4#%M=hNSr|{lSDE4qG+gYUpz+NjD16o(Ia(?XNtU2VS~Y zZb9i~)kw>u-$`yl%%B8&5Pp~;u3!fdl}(VNq+lM6+@%j7vUS4l5T=7Y44=Cacj0c| z;@Jkp)`Ff<7y&2syY#E6)ngZHE=!B;NXlhP#OLkxTtX{#i_baaBU%ZTKwa*GZ5pgc z@_jPN`Ofp$y(pd8PO%;G*luCx)xAAA2HRd?y)l@@mY4Dk!XEK#mar#1 zTS3@fc-aJ>)53n@rL={0dL@*F-RtFZgx%xWD#9APeEWr6@7WFrJM7sGQlzz!-i+vT z`(`PENSu#&Uk$ub*cHMqq&Jg>RF7cN-bz`zNo+h@t_G_LTMPR%bf$^ynf&^Qy70qXLmbZ$&UHllL`JiYX5qw!RUxgpPRzFC50=aIDGyaFp_y}a*`hm!& zp?QDm)0oeXslNiQ)IJZ~)bM3&lRDJnSX>fx9Ga(--vGWC`7-bcozc}iC%L|rdK#MV z*Utfe9AR9VcvjM!1U{Ag0ea{|^dsOi^fd5C^zT4Ty$IY*zXg7d;+W5V-o=ogPM(D+ zw40Wxon7b@I=tjL%uYo$)((4(T|AGm%{`9S{bhVjh`kSt*FZjw*L@7k-v}SC`yg1< z_o)x-8&qAu-l#WXu6pI^i{hJ5N1rW=ch{KIGw#`rCoYfls~THXe^rQehS*{K3)+T| zZB240#6F6;_+Ad{FNWB0RUf}5upL*ESQ&M{W>S}c>0d_)HTG>S7h=0%OZfTp39S)5 z@3*fCTQXqX@#{nEx4G*j4fPJLlLm?JJJYN&o&O}ew*z@rX zYEfYOb-a;k?8A|dtHpusE0NEI*q2jZQfCIXe@q>#G4#rD^;+LXyW`(b=LGEg@n=*^ z!0y(*t(FGtD~a!_c;D1cs%oC{eohf&t5_=)Ywl`8`Q-$TdI+2 z?CY2T*}(Q}y~5h-dzo(7pk5cSw>LCWjs2=VqICqeR6|7T3|K4J>VS2Et?`-6hqWPA zRso|)><}*TZIsZGT8({6ovE!0Y+nUi@3HsLP;!}enQxO4HiekNj?8b-lW5WAfSp8( z0)~7SXjk|)FonCgpKnj9L)#Lt@ziBChLn9;k8cCpq4kB>uy$pLU8ijev2krM#P(^! zAy(0@4Y8^=7Gg)VsStZWyCK9rqP^K?dMfpK?Qp=(PJOAyP|wG;clb7G?QK5OOOe0V zZV%X7B2R|c`ovZ0j=;7BQ3@EmJgpt^ZQ}D?^VnVU*xmEkJ@eRK%wzY?WA6^J7~S`( zj3-M(?p*(@-6u0ALdR7%*4Fz2woyBwy*FU1wdb_=&-3}9$4;uN8e&vq%OdB57~38S zQnHQr{|fis(_<&L`ifk1(}Xprm!*qZvGOMCc0*{KT;eyHrK1 zL-=#8u~8!p4pJC6479|@SBVJ9mOD@;vi>QxAt|qMCgN;U5@3)TAxN?M^lwMn? ziPFElioTBi>vvjXvl_3TELScfH8DbOWuz znIK;Kn}9Jo3z)=n3(K9rM%p0QEjS=}wcxdahM*;Q129In0T>pA&tK%9M-d z#d=8eheUq}`rD(oi2i$c^U@#9DE8K-R={%`cA_g(muPyR>5uk^W=u3W(d0x^70pr6 z925C#>TLRK^dDf=q9;W2J+XdI(tls9q;XjhjXg&+E-R{Wt~SxMiDso}1_X1W&xzg= z%~8=D70nYOKOypufLOC5>^~#eB{(Kn6`T`17U7m26ZwS5Cq$;G)J-rW*e2K|*dsV5 zn2WAJ&8s3G5}Xq}DtJur@n|#JctYfpkg+n=v42&^az^A!yg|rd zO=(3+L;smZbYc8If$xs|26#dJ%fL$nf1Fim!!y4p762d=_vin1;wMg?>3u zLv)uzZUt&sSy~~t0X3|IZII6eYPheQ3;8^tM(wyN+*8hjd;zWstKs>OFTz#f$?QVN zSzHyKwl0R;fh+EaK#f-8s<3W$Lhi;@!+LlLG`&FF+vrlr{XmVb#GOjvPOt&;0M=NA zJI3XZuffxh!o7muk-mYhfc!?FMi%@jx*n+Ej?n|T2-K(quZm`XsJm(fMpYZy6N9{p zbjZ;vh87OKqq_&c1C99v*LM1E^yfld5AOF1bw@>)LI1SkT!FI<{j(B1b}r6U(DHEu zO>trSjY7rj?4XUCH;j(1>l|e%H#*vDm1hdZY)`=`mpfOVPP=aHX|Gk%jVXF~`asrZZK_Z>d;?ylHz0yAK$aBW$}>cA(s7o8?Nu z*?h_9=xS6C&R0`^rI;IAO}&=5H0)UrX$w-|*X*2GE_3=du5t}+WT*WlyYHYSj@G({ zwLxmG4d=MTHF%eGF1ysdtmiP%#=e7QuHu-(Q)Z#iQ<|POiuuj?(a{ZVA|%*R%2x{J zW*VL?JLYtDUK%Z zu`(?}f1z}suV7A_MMpU287QJ>gmE2f41;sJ#vJzCZ&-zj?KXF(VLLlbI|o`!;XbUf?sD0j z9xu#}Sk8Pk)|PO$)pA^A&Pr$1G$V$MKIzA|FXjQvvYMd}U07pVN~MBn6l)5%6{fw_ zLU=-YzfN4!J*Hj8a#zdb8wZLL=xa=mQqd@!l4_SZSt%G;sAjP2o!&uDsW@RxR%~%m z^WR_MRkX(4zLG>d`wog!uG#(i?6k37<(yLuJ*Amh+nSsTnFcEu681nbr0SV6bNdQd zs%s8{v0PKh;0gwo-?wOq!wX_yaDP+owryj!ro<38rWfdTnG>dM7IUWGidu4C!|gYU zAwS+!7rkSRTLsGrS-mAt78e;NGQC{MA35$aPBv};=-mD8)C?_P!`6+mDD_%M;*{)J zQS=v#$py$KOfi+n9(+Rf~+(CHw(SWKvoVSr&TgN!;FK43YyDVfDP4QEQ~ zd!^}&V2ldqWhKma7&Ae-5p&uloG2i?EN!>OZQMo!4`E&i*=D#%St@&sLSfvM_t!1>#x3OJX^@vrxg!BbzT2ytv@LQkgy_0S&kb#pyt&h|xL{$%yux+_OQthAI_~aG$emnh zQ;~CU#D;8^IFPPX63)Ff>80>QPU49L*Vr><6erE01GvfK_Tk<(%UjLD3^-;Z?_NB{ z1#zFC6WPeFLKNLBa{~*x&3CIB;jZvDQY0G$%JO*hBh+gdlf@DOmn-`!Z*pY)6@J*X z_gkomw_;;VVp{{sH45r16{@jaCU%WEv!-zGQ#HQdZ!A^h4pu&;%d^2eE(beEo3GKF1O z9?i;ftlW0>9dyhhueoJuScqbg@+}-^)1Kye$_YJpq1~H1I%Lqfe%t}*77=ujYYI`` zUWMpzCCB5y_aEx9tT#lY9AB1^;SL>|@vcEA-P@d70Ys|88xptt8tXwg95YzB1||ke z4z_+}B;+oat%)nTn@e$ugIcJ49yJuSqnZ`QjyrwIxU9(dL-7g2l~Llj>u9MTM)7|&K5QR2zAVmu4ia* z^KLEOf}}dClA-2n5y9neRGc`;oK31(vUIT6)R6$Xxg@)xrPHp8C1lgM3@y&CO;xW; zY6$GCOPqD-nW#!Pw`ggkOfsa=hnh-ju@0q{kxRI$8jI<)hHT9i%No+aVRQ9JDuYTO zDoyK~H^z~TQy{XLp{N@sD4T{uS`lkMC9Z=MmUMy63aw@EpgNdmli!! zC)bulCgut)$xPgnT2dL^7hCExi9l{?$Rul|C5;cy*_n5s=}S?2^hP?yWiCaVscDIX za|vsjmPlnN9Ua%seb$aXYxnvLBnd702Br>COAoZ; zD?m=eF^9P;!9*GkilUKv2|hyP0go4O{I%VPcIIB&m>Db;`wr$znTfa)VNaxxPLp(( zC|Z&o>>KGR*=G05%thW-ant^F*$y~JFAAPlyw^1H#Jd>Z+%4Q-;iGXyacurgqio`9 zNkvP8J$+_%$Lh|^#hGoTsbZ$Pn77RX_>_~=ci`L4&TI$1`;;1OQnY@dWB(T9?ouv% zYwK$9=EUwT6m}R^k*3QzbdM=pShl`= zE_^I3X1=pO3ga&=3GZ8}I^Vs79q&C))pNS7IIpSV?>M9@Si|yK;2!*PGz#paU62Ow z>)0Up0I=Wvs|)(u=udxJdsFGhTHy_-d+>_y4rEV(OD|3ZuLgcY>&JW20^x-V-i}V- z-6$U`@vfQV7d8XhGVBI^MYCWnik;{)(NDsuLY*A=u%Mqjji+}?nhvzv{kN9JIR>-^ z@1_;r#g_11b_TwS_+4%g*J;#)55G?RD7l1R_{#hR59A6;;j;MHCO-U>y~v5*$)qkb z^XlrScr{-gSQ7Xxvm1#$@P)m7sJ$I1pU+OYa@qVoog?N*+9K*+2(`fX^h#xB@hfEk z|M(cgn|Dko_?Z+h9F-ZwgQGf$-!b`bS5DPs@ZP*b-koRgMm>WXm5{awsT-I_Zd2lh zZ-S++L!Lj59@o{cAu~7XzUKF-v)g|=;j@IYDu}xiYW?rme`_V?^L;Fg{KB}empt9* qn=;xrjnPy^D`*BgQyB|I@oQ>lYOAQUB%-#~4yD#lq|^SNXYcklNN1d0X8-s6 zp8xx~yYIW3ORi3?zHf72+Tza-@7$KJ`z+hJe@^Zz4Mf)vK1rf|#?GQ{(H5d8_$e6q zsUkfrb)C9K7Y=RPujc63umAk=EhAqzH}z0_{lKSMpWN2gHSiDBht8ugeZ@JK6|XAdQl7MVd6au7qH*MKqcc#EXaF#bkxqiS5;R^aF0i@c zpfpWD_e@j88=0o*LOp^Nb}hV_LYIbInk6(g;L;o+GhK2nDF@@;oi>+<`Fz^EQD`EX zsY0Vmg-)hRt`sUrcd<&SDP8X-At&vv7W&3;yI&(TFYVn7a$>YL-Do2jn0*1C4|KRz zs8VPM-9j1{W+7JaT{Mi=iN`Bq2Iw}Sf$&#S8Qm^)uh1CUKm+L-`(bE}xraib>s1TQ zN$!cZLeH=|NhiXvQnh+^Fz4sU>@-<*ly!+>?WtMkOXf_3!< z7oeN$qtMd^$7`)@<{c?{cjP7HAB?s@PZ+FkSg%1hIrf|Qa_qNpEgqrwps&$O&{OzR z^cDRDI+e~s_tDqB$|hFwCOd-VGL>R#dIHyin)7yJ5h}`3ANW}+=tS%hVf_&u4>p-4 zf-e0C#Cx7g%^=?CTv`tbWE!;sR;dbllxxMXFw-4c+APN)GZZx|vLpjF+2j6?hldzr zl%UYtkt!d(@1thxF}9U@Cpd*!YKfGp!JhYYBt}`<5Uo-}Ja0=>QI`5S zIi+f-XIA9IC`(U7KUAfjcNjFxqu+xr@#uX}S%zeBmHVh(c|>`5ln>8%^rdqCuCn-| z`bv%P%!8ncG(ALQldjBo(#04bDe}mgi78!{@vIv#C67=qs>fzL5T1YIGH98RxUTZ3 zTO>bAC^|@w&v>A6o$yhmzS2kI^h6&`&{KSLwVvjqx!RfS!^L{Ok5=hAAKk83_-Kn> zmm%x0y-PQF^t!z#OBiUYzBA+Td}&jLtOdq?eV60ma^rx$%cGC2D%I@Kzwm155t=!q z@6LGA=$1~jwG-XbiMDm3?c}8IXKCi%PUa3Dh3LKuh!=?=d*@+&pR5>zj;nI)i1&Lm zRR2b&JSx<`)em)QFfJBn8uC}`z{62f5ng~4otDlzbS$RnEFP1JK7{M4P7h)&-YylD%5YnwTymMz z`h&*vPtj!j9c!wVHvMrcUgR(VI~H?{^jQ8aV{|*X z4Fl5TX8idHn4dqNnID&NV}p*#S-db4pc5C*J7NUspBJ}%ZisBWuqYXpzcaUKw*|M1 zNnO8lNr#JCl=q!0WXp%C;Qy{=Q^Kw5TyX0C*KFJ&x?Q@JBRCg)KHN*@p73|&7V}>+ z*S-6K3+J9iR=NM(3g6amB79vVazB5LTSgJ9rY~?q8N{xl*^k17~Z>WuD9>*h~{5)W-W}QS+1ZId{C%QQgowei|7&2qk%Za(JpZZ;_ixqTuTKxE|j=P z;)KN264y$c403l#iJK(fBAJ%p@;WqeM2vRP4zX2;8!ZxDB-$jpH`IrQ29An$Kq~{) zCYL;7%B)1m;ZfM`OrRo6VN-2lhF4f{22U5^rU9Dm(7p91yXXq=n2Ws6KxW$FwdY&pYW&9tD|2+t0P>? zt$WCH&I9VhtnZrK=rcwTdy5mvfx6uo($KRJcDF})5TkQAUMAWr5=Y73*}NldFp8jG zS{>S=Nu=>p%T-W~IUDI&Tlj4;fcz9Fb~*~C*5n^^#!)$FJT?bKS3or-u*4O1tO~?e zQYGRVsK)9Yjd&tdW369?cs5kiTY*B2(-nvtpm+yBdkQPN8e7d5 zR0RDBn@S0ta{wiD9uP?4)Z@cDz57YvdBHz9W4