diff --git a/.gitignore b/.gitignore index 981d0ea..418b77d 100644 --- a/.gitignore +++ b/.gitignore @@ -398,3 +398,4 @@ FodyWeavers.xsd *.sln.iml /*.sln /FileSyncLibNet/FileSyncLibNet.sln +/FileSyncAppWin/pub diff --git a/FileSyncApp/FileSyncApp.csproj b/FileSyncApp/FileSyncApp.csproj index d233f8f..2e9b75c 100644 --- a/FileSyncApp/FileSyncApp.csproj +++ b/FileSyncApp/FileSyncApp.csproj @@ -1,4 +1,4 @@ - + Exe @@ -7,6 +7,12 @@ + + + + + + diff --git a/FileSyncApp/Program.cs b/FileSyncApp/Program.cs index a898d99..cd12c83 100644 --- a/FileSyncApp/Program.cs +++ b/FileSyncApp/Program.cs @@ -3,17 +3,60 @@ using FileSyncLibNet.FileSyncJob; using FileSyncLibNet.Logger; using FileSyncLibNet.SyncProviders; +using Microsoft.Extensions.Logging; using Newtonsoft.Json; +using Serilog; +using Serilog.Core; using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; -using System.Text.Json.Serialization; +using System.Linq; +using System.Net; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.ComTypes; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Threading; +using File = System.IO.File; namespace FileSyncApp { - internal class Program + public class Program { - static void Main(string[] args) + public static event EventHandler JobsReady; + public static volatile bool keepRunning = true; + public static LoggingLevelSwitch LoggingLevel { get; private set; } + public static ILoggerFactory LoggerFactory { get; private set; } + public static Dictionary Jobs = new Dictionary(); + public static void Main(string[] args) + { + + + + + + LoggingLevel= new LoggingLevelSwitch(Serilog.Events.LogEventLevel.Information); +#if DEBUG + LoggingLevel= new LoggingLevelSwitch(Serilog.Events.LogEventLevel.Verbose); +#endif + ConfigureLogger(); + LoggerFactory = Microsoft.Extensions.Logging.LoggerFactory.Create(builder => { builder.AddSerilog(Serilog.Log.Logger); }); + if (null!=args && args.Length > 0) + { + if (args.Contains("debug")) + { + LoggingLevel.MinimumLevel = Serilog.Events.LogEventLevel.Verbose; + } + } + Console.CancelKeyPress += (s, e) => { keepRunning = false; e.Cancel = true; }; + RunProgram(); + + } + + + static void RunProgram() { Console.WriteLine("FileSyncApp - synchronizing folders and clean them up"); Dictionary jobOptions = new Dictionary(); @@ -34,20 +77,22 @@ static void Main(string[] args) jobOptions.Add("CleanJob", cleanJob); var syncFromEdgeToLocal = FileSyncJobOptionsBuilder.CreateBuilder() - .WithSourcePath("\\\\192.168.214.240\\share\\hri\\production") + .WithSourcePath("\\\\edgeip\\share\\service\\production") .WithDestinationPath("temp") .WithFileSyncProvider(SyncProvider.SMBLib) .WithSubfolder("left") .WithSubfolder("right") .WithCredentials(new System.Net.NetworkCredential("USER", "Password", "")) - .WithInterval(TimeSpan.FromMinutes(10)+TimeSpan.FromSeconds(25)) + .WithInterval(TimeSpan.FromMinutes(10) + TimeSpan.FromSeconds(25)) .SyncRecursive(true) .Build(); jobOptions.Add("SyncFromEdgeToLocal", syncFromEdgeToLocal); - + + var hostname = Dns.GetHostName(); + var syncFromLocalToRemote = FileSyncJobOptionsBuilder.CreateBuilder() .WithSourcePath("temp") - .WithDestinationPath("Z:\\Serienspektren_Import\\53600002") + .WithDestinationPath("\\\\SERVER\\Share\\Subfolder\\" + hostname) .WithFileSyncProvider(SyncProvider.FileIO) .WithInterval(TimeSpan.FromMinutes(15)) .DeleteAfterBackup(false) //sonst werden die Daten wieder neu von der Edge geholt @@ -59,21 +104,49 @@ static void Main(string[] args) File.WriteAllText("config.json", json); } var readJobOptions = JsonConvert.DeserializeObject>(File.ReadAllText("config.json"), jsonSettings); - List Jobs = new List(); - foreach(var jobOption in readJobOptions) + //List Jobs = new List(); + + foreach (var jobOption in readJobOptions) + { + + jobOption.Value.Logger = LoggerFactory.CreateLogger(jobOption.Key); + Jobs.Add(jobOption.Key, FileSyncJob.CreateJob(jobOption.Value)); + } + JobsReady?.Invoke(null, EventArgs.Empty); + foreach (var job in Jobs) { - jobOption.Value.Logger = new StringLogger(new Action((x) => { Console.WriteLine(x); }) ); - Jobs.Add( FileSyncJob.CreateJob(jobOption.Value)); + job.Value.StartJob(); } - foreach(var job in Jobs) + Console.WriteLine("Press Ctrl+C to exit"); + while (keepRunning) { - job.StartJob(); + Thread.Sleep(200); } - Console.WriteLine("Press Enter to exit"); - Console.ReadLine(); + } + + + private static void ConfigureLogger() + { + string serilogFileTemplate = "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {SourceContext:l} {Message:lj}{NewLine}{Exception}"; + string serilogConsoleTemplate = "{Timestamp:HH:mm:ss.fff}[{Level:u3}]{SourceContext:l} {Message:lj}{NewLine}{Exception}"; + Serilog.Log.Logger = new LoggerConfiguration() + .Enrich.FromLogContext() + .WriteTo.Async(asyncWriteTo => asyncWriteTo.Console(outputTemplate: serilogConsoleTemplate), blockWhenFull: true) + .WriteTo.Async(asyncWriteTo => asyncWriteTo.File( + ("FileSyncApp.log"), + retainedFileCountLimit: 10, + fileSizeLimitBytes: 1024 * 1024 * 100, + rollingInterval: RollingInterval.Day, + outputTemplate: serilogFileTemplate), + blockWhenFull: true) + .MinimumLevel.ControlledBy(LoggingLevel) + .CreateLogger(); } + + + } } \ No newline at end of file diff --git a/FileSyncAppWin/FileSyncAppWin.csproj b/FileSyncAppWin/FileSyncAppWin.csproj new file mode 100644 index 0000000..aedd9ba --- /dev/null +++ b/FileSyncAppWin/FileSyncAppWin.csproj @@ -0,0 +1,15 @@ + + + + WinExe + net6.0-windows + + true + enable + + + + + + + \ No newline at end of file diff --git a/FileSyncAppWin/MainForm.Designer.cs b/FileSyncAppWin/MainForm.Designer.cs new file mode 100644 index 0000000..d4a7921 --- /dev/null +++ b/FileSyncAppWin/MainForm.Designer.cs @@ -0,0 +1,70 @@ +namespace FileSyncAppWin +{ + partial class MainForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm)); + textBox1 = new TextBox(); + notifyIcon1 = new NotifyIcon(components); + SuspendLayout(); + // + // textBox1 + // + textBox1.Dock = DockStyle.Fill; + textBox1.Location = new Point(0, 0); + textBox1.Multiline = true; + textBox1.Name = "textBox1"; + textBox1.ReadOnly = true; + textBox1.ScrollBars = ScrollBars.Vertical; + textBox1.Size = new Size(800, 450); + textBox1.TabIndex = 0; + // + // notifyIcon1 + // + notifyIcon1.Icon = (Icon)resources.GetObject("notifyIcon1.Icon"); + notifyIcon1.Text = "FileSyncAppWin"; + // + // MainForm + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(800, 450); + Controls.Add(textBox1); + Name = "MainForm"; + Text = "FileSyncAppWin"; + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private TextBox textBox1; + private NotifyIcon notifyIcon1; + } +} \ No newline at end of file diff --git a/FileSyncAppWin/MainForm.cs b/FileSyncAppWin/MainForm.cs new file mode 100644 index 0000000..7b0e659 --- /dev/null +++ b/FileSyncAppWin/MainForm.cs @@ -0,0 +1,75 @@ +using FileSyncLibNet.Commons; + +namespace FileSyncAppWin +{ + public partial class MainForm : Form + { + Thread consoleThread; + + public MainForm() + { + InitializeComponent(); + this.FormClosing += (s, e) => { FileSyncApp.Program.keepRunning = false; consoleThread?.Join(10_000); }; + consoleThread = new Thread(() => + { + + FileSyncApp.Program.Main(null); + }); + FileSyncApp.Program.JobsReady += (s,e)=> { + foreach(var job in FileSyncApp.Program.Jobs) + { + job.Value.JobStarted += (j, text) => + { + NewLogOutput($"{job.Key} STARTED - {text.Status} {text.Exception}"); + }; + job.Value.JobFinished += (j, text) => + { + NewLogOutput($"{job.Key} FINISHED - {text.Status} {text.Exception}"); + }; + job.Value.JobError += (j, text) => + { + NewLogOutput($"{job.Key} ERROR - {text.Status} {text.Exception}"); + }; + + } + + + }; + consoleThread.Start(); + this.Resize += ((s, e) => + { + this.SuspendLayout(); + this.BeginInvoke(() => + { + if (WindowState == FormWindowState.Minimized && ShowInTaskbar) + { + ShowInTaskbar = false; + notifyIcon1.ShowBalloonTip(10_000, "FileSyncAppWin", "I am here", ToolTipIcon.Info); + notifyIcon1.Visible = true; + } + }); + + + this.ResumeLayout(); + }); + notifyIcon1.Click += (s, e) => + { + this.BeginInvoke(() => { WindowState = FormWindowState.Normal; ShowInTaskbar = true; }); + }; + notifyIcon1.BalloonTipClicked += (s, e) => { this.BeginInvoke(() => { WindowState = FormWindowState.Normal; ShowInTaskbar = true; }); }; + //notifyIcon1.BalloonTipShown += (s, e) => { ShowInTaskbar = false; }; + + //this.WindowState = FormWindowState.Minimized; + } + + + + + private void NewLogOutput(string e) + { + + this.BeginInvoke(() => { textBox1.Text = string.Join(Environment.NewLine, (new string[] { $"{DateTime.Now.ToString("HH:mm:ss.fff")} {e}" }).Concat(textBox1.Text.Split(Environment.NewLine).Take(1000))); }); + + } + } +} \ No newline at end of file diff --git a/FileSyncAppWin/MainForm.resx b/FileSyncAppWin/MainForm.resx new file mode 100644 index 0000000..692f1df --- /dev/null +++ b/FileSyncAppWin/MainForm.resx @@ -0,0 +1,380 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + + + AAABAAMAEBAAAAEAIABoBAAANgAAACAgAAABACAAqBAAAJ4EAAAwMAAAAQAgAKglAABGFQAAKAAAABAA + AAAgAAAAAQAgAAAAAAAABAAAJRYAACUWAAAAAAAAAAAAAIo7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijoh/4k6If+KOyL/ijoh/4k6If+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/iTkg/4k5IP+IOB//mVQ//696af+ueGf/rXZk/6luXP+wemn/qG1a/4s9Jf+KOyL/ijsi/4o7 + Iv+KOyL/jkIq/5lUPv+aVkH/lU44/6BgTP+5i3z/rXZl/7J/bv+xfGz/uId4/6tyYP+LPiX/ijsi/4o7 + Iv+KOyL/iTkg/6BfS//s39v/1rqy/7B6av/Kp5v/2b+2/8Wekv/ZwLj/y6me/7qMfv/eyMH/o2RR/4k5 + H/+KOyL/ijsi/4k6If+WTzj/697a/7B7av+bWEL/xJ2Q/9vDu//l1M7/4s7I/9a6sf/cxLz/4c3H/6Nm + Uv+JOSD/ijsi/4o7Iv+KOyL/jUAn/93Gvv/j0cv/y6id/7F9bP+qcV//o2RR/6FiTv+aV0H/pmlW/6lv + Xf+YUjz/iToh/4o7Iv+KOyL/ijsi/4o6If+we2r/zqyi/82sof+kZ1T/hzYc/4k5H/+JOSD/iTkg/4g4 + H/+IOB//iToh/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/iToh/4k5IP+JOSD/ijsh/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAACAAAABAAAAAAQAgAAAA + AAAAEAAAJRYAACUWAAAAAAAAAAAAAIo7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+JOSD/iTkg/4k6If+JOiH/iTkg/4k5IP+JOiH/iToh/4k6 + IP+JOiH/iToh/4k5IP+JOSD/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/5lVP/+gX0v/lU02/5RLNP+aVkH/nVtG/5dR + Ov+UTDX/mFI8/5RMNf+XUDr/n15J/5tYQ/+LPCP/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+JOSD/vI+B/8Wekv/JpJn/xJyQ/8ii + lv/JpZn/xJyQ/7SCcv+7jX//y6id/8+vpf/MqZ7/rHNi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/iToh/4k5IP+JOSD/iTkg/4k5IP+JOSD/ijoh/4g4Hv+qcF7/xqCU/72R + g//CmIv/xJyP/7qLfP+4iHj/vpKE/8afk/+6i3z/xqCT/7N/b/+gYEv/iTkf/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+SSDH/mlZA/5pVQP+aVUD/mlZB/5tXQv+SSDD/kUcv/55c + R/+nbFn/mlZA/5FHMP+QRi7/nlxI/6BhTP+fXkr/l1E6/5pWQf+na1j/omNP/5VNN/+JOiD/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/iDgf/7WDc//z6+j/8+rn//Pr6f/t4t7/5dPO/76R + g/+xfGz/8urn/+3h3f/r3tr/zqyi/5JJMv/AlYf/9e7s/+HNx/+VTjj/wpqN/+nZ1f/p29b/49DK/6Vo + Vf+JOSD/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+IOB//qG5b//v49///////8Obj/695 + aP+YUjz/mVQ+/6VpVv/69/b/1rqy/8GXiv/9+/v/xZ6S/9W5sP/9/Pz/+/j3/8Scj/+XUjz/r3ln/9W5 + sf//////zKme/4k6If+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4k5IP+ZUz7/8efk//// + ///Gn5P/hzYc/5lUP//Em4//oF9L/+7j4P/fysP/nl1J//Xu7P/l1M7/6NnU/+rc1//XvbT/8ejl/7SB + cf/u4t//9e/t/9i9tf+laFX/iTog/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsh/45C + Kv/hzcf//////8SdkP+HNh3/kUgw/653Zf+XUTv/3MS9//jz8v/dx7///Pn5/97Iwf/y6uf/4MvE/6Vo + Vf/07er/5tXQ//Lq5//v5OD/zaqg/8CVh/+NQCj/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/iToh/86sov//////7uLe/6lwXf+TSjP/q3Jg/6pwXv+sdGL/yKOX/8ijmP+7jX7/oGBL/8GX + if+zgHD/jD8n/7WCc//Aloj/qnFf/8Objv/OrqP/uYp7/41AKP+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+IOB7/uYl6////////////+PPx/+3h3f/69/b/zqyi/4k5H/+IOB//iTkf/4g4 + H/+JOSD/iTkf/4k5IP+KOyL/iTkf/4k5H/+JOR//iDgf/4k5IP+JOSD/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4g4H/+laFT/8+vp//j08v/59PP/+fX0//r39v/bw7z/jkIp/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/45CKf+gX0v/omNP/6JjT/+iY0//omNP/51b + R/+MPiX/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4k5H/+JOR//iTkf/4k5 + H/+JOR//iTkg/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAwAAAAYAAAAAEA + IAAAAAAAACQAACUWAAAlFgAAAAAAAAAAAACKOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijwj/4w/Jv+NQCf/iToh/4s8 + I/+LPST/iToh/4w+Jv+NQCf/izwj/4s9Jf+LPCP/iz0l/4w+Jf+LPCP/iTkg/4s9Jf+MPib/jUAo/4w/ + Jv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOiH/kEUu/8uo + nf/OrKL/vZCC/6lvXf+4iXr/nl1I/8qnnP/OrKL/rnhn/76Thf+YUz3/wJaI/6pxX/+9kYP/oWJO/8Oa + jf+9kYP/0rSq/7F8a/+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/jUAn/9W5sP+vemn/z6+l/8mlmf/Ttqz/yqab/8CVh//Rsqj/wpmM/9e8s/+dXEf/1rqx/6Rm + U//ZwLj/3ce//9i+tv++koT/zKme/5BFLf+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/iTkg/8Wdkf/FnpL/0bKp/7+Thf/VubD/yKOY/9GxqP+4h3j/qG1a/9Gy + qP+we2r/2b+3/7yOgP+ueGf/49DL/8qmm/+na1j/1Leu/4w/Jv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4k6If+JOSD/iTkg/4k5 + IP+JOSD/iTkg/4k5IP+JOSD/iTkg/4o7Iv+KOyL/iDge/59eSf+/k4X/s4Bv/5JIMP+tdmT/m1hD/7J9 + bf+/lIf/pGZT/6ZqV/+sc2L/vpGE/72Qgv+YUz3/tIFx/6VoVf+QRi7/sHpq/41BKP+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijwj/5ZP + Of+bV0L/m1dC/5tXQv+bV0L/m1dC/5tXQv+bV0L/mlZA/45BKf+OQir/mlZB/5pWQP+ZVD//mFM9/5NK + M/+JOiD/iDgf/4g4H/+NQCf/mVQ//5pWQP+YUjz/ijsi/4g4H/+QRi7/m1hD/6JkUP+iY0//l1E7/4w/ + Jv+JOSD/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/izwj/82rof/17uz/8+vp//Pr6f/z6+n/9Ozq//Xu7P/17uv/8+zp/6x0Y/+bWEP/697a//Ts + 6v/07Or/9e7r/+ve2f/LqJ3/mFM9/4c3Hf+pblz/8efk//Ts6v/w5eL/rHNh/4c2HP+7jX//9/Lw//r3 + 9v/69vX/8ejl/9W4r/+cWUT/iTog/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/iDgf/8GYiv//////////////////////+vf2/9rCuv/Alon/yqaa/7J/ + bv+SSTH/6tzX///////y6ef/2L21//bw7v//////38rD/5JIMf+5inv/////////////////4MvF/5BF + Lf+laVb/1Liv/8GYi//Iopb/9e7s///////ZwLj/jkEp/4o7If+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/iDge/611ZP/8+vr////////////8+fj/vpKE/41A + J/+INx7/iDge/41AKP+MPiX/1720///////q3Nf/k0s0/7yOgP/+/f3//v7+/7iHeP/Hopb///////jz + 8v/48/H//v38/7mLfP+JOSD/kEUu/6lvXf/JpZn/9vDu///////q3Nj/k0oz/4k6If+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/iTkg/5xZRP/07Or///////// + ///iz8n/kEQs/4k6IP+MPyb/qG1b/8GYi/+OQir/wpmM///////38fD/n15K/5pVQP/07er//////9S4 + r//Zvrb//////+TRy//PrqT//////+ve2f+ZVT//x6GV//z6+f///////Pr6//Dm4/+8j4H/izwj/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijoh/5FG + Lv/m1M/////////////StKr/ijoh/4k6If+TSTL/zKqf/+rc1/+aVUD/rHRj//37+v/+/f3/toR1/6Zq + V//38e///////97HwP/n1tH//////9vCuv+fX0r/8efk///////MqZ7/4czG///////17uz/uIh5/5xZ + Q/+WTjj/jD8m/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o8I//Ttaz////////////hzMb/j0Mr/4k6If+KOyL/jD8m/51bRv+SSDH/nFlD//Ts + 6v//////8urn//Pq6P//////+/j3/8iil//w5eL//////9S3rv+KOyL/x6KW///////07er/2b+3//v4 + +P/8+vr/5dTO/+DLxP/q3Nj/pGZT/4k5H/+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4g4H/++koT////////////69/b/uIh5/4o8I/+INx7/iDce/5tX + Qv+tdmT/kEUt/8+vpf/hzcf/4c3G/+HNxv/Zv7f/tYJz/55dSP/Zv7f/4MvF/7qMfv+IOB//m1dB/9i9 + tf/gy8T/vpKE/7OAcP/XvbT/59fS/+na1v/cxb7/pGZS/4k5IP+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4g4H/+qcV//+/n4////////////9/Lx/9Gx + p/+3h3j/wpmM/+vd2f/bwrr/jD8m/4w/J/+OQSn/jkEp/45BKf+MPiX/iTkf/4o8I/+NQCf/jUAo/4s+ + Jf+KOyL/ijsi/4w/Jv+NQCj/jD8n/4k5H/+LPSX/kEUu/5FHL/+NPyf/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4k5IP+aVkH/8unm//// + ///////////////////////////////////s39v/lU02/4k6IP+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijoh/4o6If+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o6 + If+PRCz/49DL///////////////////////////////////////49PL/o2VS/4g4H/+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KPCP/vI+B/9rBuf/Zv7f/2b+3/9m/t//Zv7f/2b+3/9m/t//YvbX/pGdU/4k5 + H/+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/izwj/4s9Jf+LPST/iz0k/4s9JP+LPST/iz0k/4s9 + JP+LPSX/izwj/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7Iv+KOyL/ijsi/4o7 + Iv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + + + \ No newline at end of file diff --git a/FileSyncAppWin/Program.cs b/FileSyncAppWin/Program.cs new file mode 100644 index 0000000..0768b4e --- /dev/null +++ b/FileSyncAppWin/Program.cs @@ -0,0 +1,17 @@ +namespace FileSyncAppWin +{ + internal static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + // To customize application configuration such as set high DPI settings or default font, + // see https://aka.ms/applicationconfiguration. + ApplicationConfiguration.Initialize(); + Application.Run(new MainForm()); + } + } +} \ No newline at end of file diff --git a/FileSyncAppWin/buildcommand.cmd b/FileSyncAppWin/buildcommand.cmd new file mode 100644 index 0000000..bed8bb5 --- /dev/null +++ b/FileSyncAppWin/buildcommand.cmd @@ -0,0 +1 @@ +dotnet publish -o pub -c Release -p:PublishSingleFile=true -p:PublishTrimmed=false -r win-x86 --self-contained .\FileSyncAppWin.csproj diff --git a/FileSyncLibNet/FileSyncJob/FileSyncJob.cs b/FileSyncLibNet/FileSyncJob/FileSyncJob.cs index 20500ec..39cde72 100644 --- a/FileSyncLibNet/FileSyncJob/FileSyncJob.cs +++ b/FileSyncLibNet/FileSyncJob/FileSyncJob.cs @@ -85,14 +85,14 @@ private void RunJobInterlocked() try { //True Job Code - options.Logger.LogDebug("start job {0}", JobName); + options.Logger.LogInformation("start job {0}", JobName); if (options is IFileSyncJobOptions) syncProvider.SyncSourceToDest(); else if (options is IFileCleanJobOptions) syncProvider.DeleteFiles(); else throw new NotImplementedException($"job with options type {options.GetType()}"); - options.Logger.LogDebug("end job {0}", JobName); + options.Logger.LogInformation("end job {0}", JobName); } catch (Exception exc) { diff --git a/FileSyncLibNet/FileSyncJob/FileSyncJobOptions.cs b/FileSyncLibNet/FileSyncJob/FileSyncJobOptions.cs index f0edc53..89896d4 100644 --- a/FileSyncLibNet/FileSyncJob/FileSyncJobOptions.cs +++ b/FileSyncLibNet/FileSyncJob/FileSyncJobOptions.cs @@ -12,6 +12,7 @@ public class FileSyncJobOptions : FileJobOptionsBase, IFileSyncJobOptions public string SourcePath { get; set; } public bool SyncDeleted { get; set; } = false; public bool DeleteSourceAfterBackup { get; set; } = false; + public bool RememberLastSync { get; set; } = true; public FileSyncJobOptions() { diff --git a/FileSyncLibNet/FileSyncJob/FileSyncJobOptionsBuilder.cs b/FileSyncLibNet/FileSyncJob/FileSyncJobOptionsBuilder.cs index 1c8a480..7a1badc 100644 --- a/FileSyncLibNet/FileSyncJob/FileSyncJobOptionsBuilder.cs +++ b/FileSyncLibNet/FileSyncJob/FileSyncJobOptionsBuilder.cs @@ -53,6 +53,11 @@ public IFileSyncJobOptionsBuilderSetProperties SyncDeleted(bool syncDeleted) jobOptions.SyncDeleted = syncDeleted; return this; } + public IFileSyncJobOptionsBuilderSetProperties RememberLastSync(bool rememberLastSync) + { + jobOptions.RememberLastSync = rememberLastSync; + return this; + } public IFileSyncJobOptionsBuilderSetProperties WithCredentials(string username, string password) { diff --git a/FileSyncLibNet/FileSyncJob/IFileSyncJobOptions.cs b/FileSyncLibNet/FileSyncJob/IFileSyncJobOptions.cs index 49f4d18..0c348b5 100644 --- a/FileSyncLibNet/FileSyncJob/IFileSyncJobOptions.cs +++ b/FileSyncLibNet/FileSyncJob/IFileSyncJobOptions.cs @@ -1,16 +1,12 @@ using FileSyncLibNet.Commons; -using FileSyncLibNet.SyncProviders; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.Net; namespace FileSyncLibNet.FileSyncJob { - public interface IFileSyncJobOptions: IFileJobOptions + public interface IFileSyncJobOptions : IFileJobOptions { string SourcePath { get; set; } bool DeleteSourceAfterBackup { get; set; } bool SyncDeleted { get; set; } + bool RememberLastSync { get; set; } } } \ No newline at end of file diff --git a/FileSyncLibNet/FileSyncLibNet.csproj b/FileSyncLibNet/FileSyncLibNet.csproj index 139c18b..56c42cd 100644 --- a/FileSyncLibNet/FileSyncLibNet.csproj +++ b/FileSyncLibNet/FileSyncLibNet.csproj @@ -13,7 +13,7 @@ - + diff --git a/FileSyncLibNet/SyncProviders/FileIOProvider.cs b/FileSyncLibNet/SyncProviders/FileIOProvider.cs index 6884568..c53bbd5 100644 --- a/FileSyncLibNet/SyncProviders/FileIOProvider.cs +++ b/FileSyncLibNet/SyncProviders/FileIOProvider.cs @@ -45,7 +45,13 @@ public override void SyncSourceToDest() searchPattern: JobOptions.SearchPattern, searchOption: JobOptions.Recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly); - + if (jobOptions.RememberLastSync) + { + var old = _fi.Count(); + _fi = _fi.Where(x => x.LastWriteTime > (LastRun - jobOptions.Interval)).ToList(); + skipped += old-_fi.Count(); + LastRun = DateTimeOffset.Now; + } foreach (FileInfo f in _fi) { diff --git a/FileSyncLibNet/SyncProviders/ProviderBase.cs b/FileSyncLibNet/SyncProviders/ProviderBase.cs index c82c32a..1138280 100644 --- a/FileSyncLibNet/SyncProviders/ProviderBase.cs +++ b/FileSyncLibNet/SyncProviders/ProviderBase.cs @@ -1,10 +1,6 @@ using FileSyncLibNet.Commons; -using FileSyncLibNet.FileSyncJob; using Microsoft.Extensions.Logging; using System; -using System.Collections.Generic; -using System.Net; -using System.Text; namespace FileSyncLibNet.SyncProviders { @@ -12,7 +8,7 @@ internal abstract class ProviderBase : ISyncProvider { internal ILogger logger => JobOptions.Logger; public IFileJobOptions JobOptions { get; } - + internal DateTimeOffset LastRun { get; set; } = DateTimeOffset.FromUnixTimeMilliseconds(0).ToLocalTime(); public abstract void SyncSourceToDest(); public abstract void DeleteFiles(); public ProviderBase(IFileJobOptions jobOptions) diff --git a/FileSyncLibNet/SyncProviders/SmbLibProvider.cs b/FileSyncLibNet/SyncProviders/SmbLibProvider.cs index dda1b4b..40573bf 100644 --- a/FileSyncLibNet/SyncProviders/SmbLibProvider.cs +++ b/FileSyncLibNet/SyncProviders/SmbLibProvider.cs @@ -5,6 +5,7 @@ using SMBLibrary.Client; using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using FileAttributes = SMBLibrary.FileAttributes; @@ -32,7 +33,9 @@ public override void SyncSourceToDest() { if (!(JobOptions is IFileSyncJobOptions jobOptions)) throw new ArgumentException("this instance has no information about syncing files, it has type " + JobOptions.GetType().ToString()); - + var sw = Stopwatch.StartNew(); + int copied = 0; + int skipped = 0; //Determine if source or destination is network path bool sourceIsNetShare = jobOptions.SourcePath.StartsWith("\\\\"); bool destIsNetShare = jobOptions.DestinationPath.StartsWith("\\\\"); @@ -78,9 +81,14 @@ public override void SyncSourceToDest() searchPattern: JobOptions.SearchPattern, searchOption: JobOptions.Recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly); + if (jobOptions.RememberLastSync) + { + _fi = _fi.Where(x => x.LastWriteTime > (LastRun - jobOptions.Interval)); + LastRun = DateTimeOffset.Now; + } if (jobOptions.SyncDeleted) { - var remoteFiles = ListFiles(DestinationPath, true); + var remoteFiles = ListFiles("", DestinationPath, true, jobOptions.RememberLastSync ? LastRun - jobOptions.Interval : DateTime.MinValue, out _); foreach (var file in remoteFiles) { var realFilePath = file.Substring(file.IndexOf(DestinationPath) + DestinationPath.Length).Trim('\\').Replace('/', '\\'); @@ -101,6 +109,7 @@ public override void SyncSourceToDest() try { WriteFile(f.FullName, remotefile); + copied++; if (jobOptions.DeleteSourceAfterBackup) { File.Delete(f.FullName); @@ -113,7 +122,10 @@ public override void SyncSourceToDest() } else + { logger.LogDebug("Skip {A}", relativeFilename); + skipped++; + } } } } @@ -149,24 +161,26 @@ public override void SyncSourceToDest() searchPattern: JobOptions.SearchPattern, searchOption: JobOptions.Recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly); - var remoteFiles = ListFiles(Path.Combine(SourcePath, dir.Name), JobOptions.Recursive); + var remoteFiles = ListFiles(SourcePath, dir.Name, JobOptions.Recursive, jobOptions.RememberLastSync ? LastRun - jobOptions.Interval : DateTime.MinValue, out int skippedByTimestamp); + skipped += skippedByTimestamp; + LastRun = DateTimeOffset.Now; if (jobOptions.SyncDeleted) { foreach (var file in remoteFiles) { - var realFilePath = file.Substring(file.IndexOf(SourcePath) + SourcePath.Length).Trim('\\').Replace('/', '\\'); + var realFilePath = file.Trim('\\').Replace('/', '\\'); if (!_fi.Any(x => x.FullName.Replace('/', '\\').EndsWith(realFilePath))) File.Delete(file); } } - foreach (var remoteFile in remoteFiles) + foreach (var remoteFileFromSource in remoteFiles) { bool copy = false; - var realFilePath = remoteFile.Substring(remoteFile.IndexOf(SourcePath) + SourcePath.Length).Trim('\\').Replace('/', '\\'); - + var realFilePath = remoteFileFromSource.Trim('\\').Replace('/', '\\'); + var remoteFileWithSource = Path.Combine(SourcePath, remoteFileFromSource).Trim('\\'); var localFile = Path.Combine(jobOptions.DestinationPath, realFilePath.TrimStart('\\', '/')).Replace('/', '\\'); var exists = File.Exists(localFile); - _ = FileExists(remoteFile, out long remoteSize); + _ = FileExists(remoteFileWithSource, out long remoteSize); var size = exists ? new FileInfo(localFile).Length : 0; copy = !exists || size != remoteSize; if (copy) @@ -174,10 +188,11 @@ public override void SyncSourceToDest() logger.LogDebug("Copy {A}", realFilePath); try { - ReadFile(remoteFile, localFile); + ReadFile(remoteFileWithSource, localFile); + copied++; if (jobOptions.DeleteSourceAfterBackup) { - DeleteFile(remoteFile); + DeleteFile(remoteFileWithSource); } } catch (Exception exc) @@ -187,12 +202,17 @@ public override void SyncSourceToDest() } else + { logger.LogDebug("Skip {A}", realFilePath); + skipped++; + } } } } + sw.Stop(); + logger.LogInformation("{A} files copied, {B} files skipped in {C}s", copied, skipped, sw.ElapsedMilliseconds / 1000.0); } @@ -227,7 +247,7 @@ public void ConnectToShare(string server, string shareName, string domain, strin } - + } public void Dispose() @@ -340,12 +360,13 @@ void DeleteFile(string filePath) } } - List ListFiles(string subPath, bool recurse) + List ListFiles(string sourcePath, string sourcesubPath, bool recurse, DateTimeOffset maxAge, out int skipped) { List retval = new List(); object directoryHandle; FileStatus fileStatus; - var status = fileStore.CreateFile(out directoryHandle, out fileStatus, subPath.Trim('\\'), AccessMask.GENERIC_READ, FileAttributes.Directory, ShareAccess.Read | ShareAccess.Write, CreateDisposition.FILE_OPEN, CreateOptions.FILE_DIRECTORY_FILE, null); + skipped = 0; + var status = fileStore.CreateFile(out directoryHandle, out fileStatus, Path.Combine(sourcePath, sourcesubPath).Trim('\\'), AccessMask.GENERIC_READ, FileAttributes.Directory, ShareAccess.Read | ShareAccess.Write, CreateDisposition.FILE_OPEN, CreateOptions.FILE_DIRECTORY_FILE, null); if (status == NTStatus.STATUS_SUCCESS) { List fileList; @@ -364,14 +385,21 @@ List ListFiles(string subPath, bool recurse) { try { - retval.AddRange(ListFiles(Path.Combine(subPath.Trim('\\'), file.FileName), recurse)); + retval.AddRange(ListFiles(sourcePath,Path.Combine(sourcesubPath, file.FileName).Trim('\\'), recurse, maxAge, out int moreSkipped)); + skipped += moreSkipped; } catch { } } } else { - retval.Add(Path.Combine(subPath.Trim('\\'), file.FileName)); + if (file.LastWriteTime > maxAge) + retval.Add(Path.Combine(sourcesubPath.Trim('\\'), file.FileName)); + else + { + skipped++; + //logger.LogTrace("Skipping {0} because it should have been synced last time", file.FileName); + } } } @@ -434,7 +462,7 @@ void GetFileAttributes(string filepathFromShare, out DateTime lastWriteTime, out } else { - throw new Exception("unable to set attributes - status " + status); + throw new Exception("unable to get attributes - status " + status); } }