From 75ac9259b178c08308a9402e1a3fd921e17375d5 Mon Sep 17 00:00:00 2001 From: Thomas Nind Date: Wed, 23 Oct 2019 14:18:13 +0100 Subject: [PATCH 01/19] Added initial work on UI for dicom repopulator (does not Start) --- TemplateBuilder/Form1.Designer.cs | 20 +- TemplateBuilder/Form1.cs | 11 + TemplateBuilder/Form1.resx | 124 ++++---- .../Repopulator/CsvToDicomTagMapping.cs | 104 ++++++ .../Repopulator/DicomRepopulatorProcessor.cs | 194 +++++++++++ .../Repopulator/RepopulatorUI.Designer.cs | 300 ++++++++++++++++++ TemplateBuilder/Repopulator/RepopulatorUI.cs | 121 +++++++ .../Repopulator/RepopulatorUI.resx | 120 +++++++ .../Repopulator/RepopulatorUIState.cs | 20 ++ TemplateBuilder/RepopulatorUI.resx | 120 +++++++ TemplateBuilder/TemplateBuilder.csproj | 1 + 11 files changed, 1068 insertions(+), 67 deletions(-) create mode 100644 TemplateBuilder/Repopulator/CsvToDicomTagMapping.cs create mode 100644 TemplateBuilder/Repopulator/DicomRepopulatorProcessor.cs create mode 100644 TemplateBuilder/Repopulator/RepopulatorUI.Designer.cs create mode 100644 TemplateBuilder/Repopulator/RepopulatorUI.cs create mode 100644 TemplateBuilder/Repopulator/RepopulatorUI.resx create mode 100644 TemplateBuilder/Repopulator/RepopulatorUIState.cs create mode 100644 TemplateBuilder/RepopulatorUI.resx diff --git a/TemplateBuilder/Form1.Designer.cs b/TemplateBuilder/Form1.Designer.cs index dabf2be..085c89a 100644 --- a/TemplateBuilder/Form1.Designer.cs +++ b/TemplateBuilder/Form1.Designer.cs @@ -52,6 +52,7 @@ private void InitializeComponent() this.miWindowFiles = new System.Windows.Forms.ToolStripMenuItem(); this.miWindowTable = new System.Windows.Forms.ToolStripMenuItem(); this.dockPanel1 = new WeifenLuo.WinFormsUI.Docking.DockPanel(); + this.tagPopulatorToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); ((System.ComponentModel.ISupportInitialize)(this.olvDicoms)).BeginInit(); this.toolStrip1.SuspendLayout(); this.SuspendLayout(); @@ -209,35 +210,36 @@ private void InitializeComponent() this.miWindowYaml, this.miWindowSql, this.miWindowFiles, - this.miWindowTable}); + this.miWindowTable, + this.tagPopulatorToolStripMenuItem}); this.toolStripDropDownButton1.Image = ((System.Drawing.Image)(resources.GetObject("toolStripDropDownButton1.Image"))); this.toolStripDropDownButton1.ImageTransparentColor = System.Drawing.Color.Magenta; this.toolStripDropDownButton1.Name = "toolStripDropDownButton1"; this.toolStripDropDownButton1.Size = new System.Drawing.Size(29, 22); this.toolStripDropDownButton1.Text = "toolStripDropDownButton1"; // - // templateyamlToolStripMenuItem + // miWindowYaml // this.miWindowYaml.Name = "miWindowYaml"; this.miWindowYaml.Size = new System.Drawing.Size(180, 22); this.miWindowYaml.Text = "Template (yaml)"; this.miWindowYaml.Click += new System.EventHandler(this.WindowClicked); // - // templateSqlToolStripMenuItem + // miWindowSql // this.miWindowSql.Name = "miWindowSql"; this.miWindowSql.Size = new System.Drawing.Size(180, 22); this.miWindowSql.Text = "Template (sql)"; this.miWindowSql.Click += new System.EventHandler(this.WindowClicked); // - // fileListToolStripMenuItem + // miWindowFiles // this.miWindowFiles.Name = "miWindowFiles"; this.miWindowFiles.Size = new System.Drawing.Size(180, 22); this.miWindowFiles.Text = "Dicom File List"; this.miWindowFiles.Click += new System.EventHandler(this.WindowClicked); // - // dataGridToolStripMenuItem + // miWindowTable // this.miWindowTable.Name = "miWindowTable"; this.miWindowTable.Size = new System.Drawing.Size(180, 22); @@ -251,6 +253,13 @@ private void InitializeComponent() this.dockPanel1.Size = new System.Drawing.Size(200, 100); this.dockPanel1.TabIndex = 11; // + // tagPopulatorToolStripMenuItem + // + this.tagPopulatorToolStripMenuItem.Name = "tagPopulatorToolStripMenuItem"; + this.tagPopulatorToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.tagPopulatorToolStripMenuItem.Text = "Tag Populator"; + this.tagPopulatorToolStripMenuItem.Click += new System.EventHandler(this.tagPopulatorToolStripMenuItem_Click); + // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -294,6 +303,7 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem miWindowFiles; private System.Windows.Forms.ToolStripMenuItem miWindowTable; private WeifenLuo.WinFormsUI.Docking.DockPanel dockPanel1; + private System.Windows.Forms.ToolStripMenuItem tagPopulatorToolStripMenuItem; } } diff --git a/TemplateBuilder/Form1.cs b/TemplateBuilder/Form1.cs index 0fafbbf..2ca0021 100644 --- a/TemplateBuilder/Form1.cs +++ b/TemplateBuilder/Form1.cs @@ -440,6 +440,17 @@ private void WindowClicked(object sender, EventArgs e) else dc.Show(dockPanel1,DefaultDockLocations[dc]); } + + private void tagPopulatorToolStripMenuItem_Click(object sender, EventArgs e) + { + var ui = new Repopulator.RepopulatorUI(); + + var dc = new DockContent(); + ui.Dock = DockStyle.Fill; + dc.Controls.Add(ui); + dc.TabText = "Repopulator"; + dc.Show(dockPanel1,DockState.DockTop); + } } internal class TagValueNode diff --git a/TemplateBuilder/Form1.resx b/TemplateBuilder/Form1.resx index 7acb0a4..a4449ab 100644 --- a/TemplateBuilder/Form1.resx +++ b/TemplateBuilder/Form1.resx @@ -144,55 +144,56 @@ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIUSURBVDhP3Y+7a1NRHMfP4N7NP8HBmvpIGxUHF0EctIvo - oE4iaAkoEQqKoB3SRoRIaXQQqYilgq2VVhHEITjV9HXT5trcPFqbpsYmtLnvR+7r67ntVZLFVfBwPpxz - hs/3+zvkP1nLH4Lp0tRZc32qu4lzZuHjsZXi2469K2+CbS18DrYlkyf3+DohqVchw3UdAC7dHrt3S69h - I9nTKE9fMn5Tmb+pl6YjJW7yyAVfJ4R91yW4tg5jIw51dRDq2gtopXG4Fk+zFLi2TBF331Yd9a1qg5sI - sb5OSH70sOSYIpUTUIpDkL71YXumB7XZMPhMFPzSA/Dpu6gzvZQInayK/ESn7Os0YKzLtLRN8GwC9YUY - ql9uQ6umaKvkt3un8GcC73vM2EHd170Jjpo7/3cMigbY6o5oaxyMSgJ6OQrtey/UwnUo3GXYShbMSHNA - ItRwbQ229BUW/wnm1jgam8+p+Aja2j1oxTDU3BUoy92QM6dgy2kwj5sCUs9ChmNKMLffo1Edoa1PoK/T - 1lWv9RqU7EXI7BlIiycgLhyCJc21BngP1+Sp/BLGj0HopT4qR6Dmr1L5PG09DSl9HOJ8B4TZfTRgpjUg - 9zBQ0QRWKM+9dpTCMOT8U8hcHHK2HxJ7H1LmDsSlCMR0GCJzAz9zky4bDwq+TgjX336Lix0YZQf215hY - QP8rAwF9MRYQuWj7kK//00XIL/Y/55GFrGySAAAAAElFTkSuQmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIWSURBVDhP3Y/NaxNBHIbn4L03/wQP1tSPtFHx4EUQwY+L + 6EE9iaAloEQoKIL2kDYiREqjBymKWCrYWrWKIB6Cp8bGdtNmbbZJWpu0hm402e+P7G72dbZdJbl4FRzm + YWYOz/v+hvwna/FdMFOaOm6Vp062cMIqvD+wXHzZtX35RbCjjY/BjmTy8DZfJyT1LGS6bhOAS7fH1t02 + qlhP9jbWps+Zv6nMXjVK05ES92bfGV8nhH3VI7qOAXM9Dm1lCNrqE+ilCbi2QLNUuI5Ckbbedh21H3yD + mwyxvk5Ifmyv3LQkKiegFochf+1HbaYX1XQYQjYKYeEOhMxN1Jk+SoROxiM/2a34Og0Y77FsfQMCm0B9 + Lgb+03Xo/GfaKvvt3in+mcD7HjO+2/B1b4L91ub/myZFBxxtU3R0DmYlAWMtCv1bH7TCZajceThqDsxo + a0Ai1HAdHY6cgi18gPVzAo2NESreg756C3oxDG3pAtTFU1CyR+AoGTD3WwJSj0Jm05Jh1d6iwY/S1gcw + yrR1xWu9BDV3Fgp7DPL8IUhze2DLX9oDvIdrCVR+CvP7EIxSP5Uj0PIXqXyath6FnDkIabYLYnoHDZhp + D1i6G6joIiuW08+bauExlPxDKFwcSm4AMnsbcvYGpIUIpEwYEnMFFe61y8aDoq8Twg10XuNiu8bYwZ1V + JhYw/spgwJiPBSQu2jns6/90EfIL2BPng2ubD2wAAAAASUVORK5CYII= iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAORSURBVDhPZZJrTJN3FMbfRDdjNrN9MlvCXOIWs5kw0qDT - ISxbyIgjE3WmGkAuldEyaF/lIkYcUoHNDlZpF6YIVGlrAUHtjRbE3igtpfZOW1ooKw6Zg24Mw4YzsuRZ - 6bov85ecb+d3zvPP/xD/h2kqTGOZaH1lo7TZEhPtT9KU+5TU0xZJE03BMhbsj7c9T52+biNpLLyxLtz7 - SQJ7ZBi6B2YMTJshC2hxK9CNAkXeGn04W12qp74c1/6Fbqe/EN1gEgW/w8KqA9NLPniXnJDOuqAKT0Lk - 80HodqLPbQLfehG5dw55qH3UV+I6QUQjS7oCFxFeMWByxQL/sh+uRTe6Q370h2fAc4TQPB7ApRErpH4t - +JYafC7KVMdkcpSWSg5Rn839YcDAsgq3HqswuDSCwYc+dAan8IN3GiyVAyylBY02FdpnW+H4RYqPW1L+ - zmz96CARjX5bFW6D/VcVepbluPm7FdaIB1yXH822KdAHHGBoNCifbEdluB7lMzUQu/m4Mc5Bekvq3fX4 - cxO/KSGa6wA3Iohu98EScYO86wJdbsdpqw2MUDUOTNFxIFCMPC8T5+9VwhiS4EPO3kcEqc9enXmsQ0Pw - AlihM2j/WY+eWTvyeu+DqTWieXoIhcFulPSkovg6BYc02WD2F8E5r8AHdTufEEVDhU9+XNah1lMJpoeH - aw80yO+xIF/mxZGrYyA1Y6jxSPGFaB8uKHNwrO0dMMQ5cD6UI6ki6S+iVJ8971qUgedrQNOMHvW2URwV - 2XFSkgaWOAUM4W7QBBR8JaWiz8ZHVf9BZLS8Bk1QCEpN0gJRPJyjkAa+x0C4C6fGGsF29+K4xIwy8R7I - nJdx29EaE3ttPPA0VRBamlAiycAezmZQzibqiROKYxl54iNr3ogKVZovUa4lwVLrUBR977p8afgkvh0q - w9dqOthKGupVDLQZG3C8KxVvVhJrsVs42vuZnGuohjJwFWzDWZw3apDb8S5u3udBMs6FcKwJ18yc6JBS - XDHWgy7Zj7cqXlxNKCc2xwZkdWZtyWz7xPPN4ClYFu6ga8KAw1e241N+QvSvt2Jf86vIv56CyyNsnBBn - YGvtpqc7z2zfFpP/I6szZUs6N02d3PTemsDcAYFRic4RLQSjOsgnZNjFeQkFwnS8cW7TSmL12wlx7Xn2 - Nu4+/D47eTC5ljK/o2LH6nolnk589Hrthmfbzm0AUUdsjLdGIYh/AFnrU1wnTWqJAAAAAElFTkSuQmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAOSSURBVDhPZZJtTJNnFIbfRDdjNrP92bIlzCVuMZtJQzp1 + KsJiQkYcmahzaAD5qIyWQftqATHikApsdrBiuzBFoEpbCwhqW0pbxH5RWkrtNy20UFYcMgfdGIYNZ2TJ + vdJ1f+aVnH/nOud+8hzi/zDNBSksM62ndJg2U2ym/Umac56SBtoCaab1sUz5++Ntz1NjqFlPmgpurAn3 + fpLCERmE/oEF/VMWyAM63Ap0Il+Ru0ofzFKXGDJfjmv/QnfQX4huMIuD32F+xYmpRT98iy7IZtxQhScg + 9vsh8rjQ4zFDYLuInDuHvJk9ma/EdYKIRpZ2BC4ivGzExLIV40vjcC940BkaR294GnxnCI2jATQN2SAb + 10FgrcJn4nR1TCaHacmk5vNns38Y0b+kwq3HKmgWh6B56Ed7cBI/+KbAUjnBUlpRb1ehdaYZzl9k2Ne0 + 5+/05n0HiWj026pwCxy/qtC1pMDN322wRbzgucfRaJ8Evd8JhlYL9kQrysO1YE9XQeIR4MYoF6mXku+u + xZ8d+00J8WwbeBFhdLsf1ogH5F036AoHTtvsYIQqcWCSjgOBIuT6mDh/rxymkBQfcXc/IkhD1sr0Yz3q + ghfACp1B688GdM04kNt9H0ydCY1TAygIdqK4KxlF16k4pM0Cs7cQrrk+7KnZ9oQoHCh48uOSHtXecjC9 + fFx7oEVelxV5ch+OXB0BqR1BlVeGL8R7cUGZjWMt74EhyYbroQKJ7MS/iBJD1px7QQ6+vw4N0wbU2odx + VOzASWkKWJIkMEQ7QRNS8ZUsEz12ASp6DyLt0hvQBkWgViXOE0WD2X2ywPfoD3fg1Eg9OJ5uHJdaUCrZ + BbnrMm47m2Nit50PvrYCImsDiqVp2MXdCOpZioE40XcsLVd8ZNUXUaFC+yXYOhIstR6F0feuyU2DJ/Ht + QCm+VtPBUdJQq2KgxVSH4x3JeLuMWI3dwtHuTxU8YyWUgavgGM/ivEmLnLb3cfM+H9JRHkQjDbhm4UaH + lOCKqRZ06X68U/biSgKb2BgbkNGesSm95WPvN5pTsM7fQceYEYevbMEngoToX7+OvY2vIu96Ei4PcXBC + kobXqjc83XZmy+aY/B8Z7UmbUnkp6g8aKKtCSxuEJiXah3QQDuuhGJNjB/cl5ItS8da5DcuUyncT4trz + 7K7fefhDznbN9mrq3NayrStrRTlNefRm9bpnm8+tA1FDrI+3RiGIfwBCS1NQe45Z+wAAAABJRU5ErkJg + gg== iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAKqSURBVDhPjZJZTxNRHMX7hXygy+ASv4WPxrAVugABRGTT - aOKDGkGi0QhF0EJYZV/tAJoqQqFigWDK0tIWoRS6A53S7fifW+WJECY5uZmZe37n3EXCafhShYZvkGt5 - M8nPaYdjnHYgxWl50D+ma4VTuFE8jetFPDILJgI3i/lFmWb8lkR8ODWvW3ZEsOwQEI2nIJAip0kETxI4 - CMbgC8fZuxBL4jAUx6rNmxqyOOJ3nhm9nHo0V8JpDdbl7Qge9XgQiZGZJua9mIf/KI4DMoQjCQYO0ejy - nmLTHYXB4se0xQuuhI8SYCpoIcDDrn02SZQI8IRi8B/HWbLYYJ/a2Paj2NwTUN3mxLe1ABTq3hQBhmNm - 2wkB3GySqPw6Ezw0HkWTiFKrwHEC2x4xXcD6roBKvQPdRjcUqnEQYCBl2jrGg043nFRR1I7vlNITLP1I - SGLXFzszW3cjuP/BjvaZP5AXjIoAHnPrBOjYY9WVlF5Qb0Lhq0UUkdQNC1DSd/Hff5U3b6DV4IQ8f4QA - dEyz1jBq2ndobSQaa9pdqGkT5USV3kmJ26hotaO8xYay5k2Uv99C05gNcuVQGmBcC6fNpLSRRBDRXPnR - wSrfayEAGe/qNkjreDO4AVneQBowsxIks+ufnGfpzEzJFa02Zi4jY2mjFSWNv1HfuwZZbp8IMIC3BFCt - d7HzvoyK3q7ieecKpDm9kFylTZxcCrC6Ah3Z0685F0q8E5rXv/CkbQnS7B4CFPIYN/upQRpg3PpyoUSA - quEnHreYCdAFSaa2PzWy4COA49INlHULqNWZkJGlS0mkKoO978ch+mYPzl3veaptmkfVuzlk3Nb7JAr1 - 55cK9eSYPHvSr1BN0PUcYzdMnj8MmXKQjqof0txPtGE9VLmbUrtY8pWsjlBGdsf3v9/sEQvg31m2AAAA - AElFTkSuQmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAKrSURBVDhPjZJZTxNRHMX7hXygy+ASv4WPxrAVugABRGTT + aOKDGkGi0cgiaCEsxSKy2wE0VYRCxYLBFGjpwlIKdAU6pdvxP7fKEyFMcnIzM/f8zrmLhNPw5QoN3yTX + 8hZSgNMOxTntQJrT8qB/TFeKJ3GtdApXS3hkF40Hr5fyCzLN2A2J+HBqvnXJFcWSS0AskYZAip6kEDpO + Yi8Uhz+SYO9CPIX9cALL9v30oNWZuPXEdMCpR/IlnNZoW3JG8UDvQzROZppY8GwOgcME9sgQiSYZOEyj + 5+AE694YjNYApqwH4Mr4GAEmQ1YC3O/dZZNEiQBfOI7AUYIliw12qY1jN4b1HQG1nW58WwlCodanCTAU + tziOCeBlk0QVNpjho/EwlkKMWgWPknD6xHQBq9sCqnUu9Jm8UKjGQICBtNl+hHs9XripoqhN/wmlJ1n6 + oZDCtj9+arZtR3H33Qa6prcgLxoRATxmVwnQvcOqKym9qNGM4hcLKCGpm+ahpO/iv/+qbFtDh9ENeeEw + AeiYZmwR1HVt0tpINNZ1eVDXKcqNGp2bEp2o6thAZbsDFW3rqHxrR8uoA3LlpwzAtBLJmEkZI4kgorn6 + vYtVvtNOADLebl0jreLV4BpkBR8zgOnlEJk9/+Q+TWdmSq7qcDBzBRnLm20oa/6Dxv4VyPINIsAI3hpE + rc7DzvsiKnn9G097liHN64fkMm3ixGKQ1RXoyB5/zTtX4p3QvPyFR52LkObqCVDMY8wSoAYZgMn+5VyJ + AFXTTzxstxCgF5JsrSE9PO8ngOvCDZQN86hvNSMrpyUtkaqMG4Yf+zDM7J253rNU3zKHmjezyLqp80sU + 6s/PFeqJUXnuREChGqfrOcpumLxwCDLlIB3VAKT5H2jD9FS5j1J7WfKlnO5wVm7397/CxhEAhIrZQwAA + AABJRU5ErkJggg== @@ -215,34 +216,33 @@ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAALeSURBVDhPVZFdSJNhGIZ3VOedeRR1FFGpkRl1ItJMlyBk - 1lE1zak1KkQkogRbmppTSzAEozryoBBy/qDbVPzZ1NI0N7dV5t/c/Jlz/3u3fZt37/duTn3g5vneg/t6 - 7uf5BHwJXwyLs+snVDnyiZ3M6gk/7YSpge+TJKd+nIjqNPor5aPvTud9OcJMByuremx0y0221+2usN0b - gN2zr203LwKj1Y0KxSruNph8mY96j8as0bpeq9myOTzh8eUQJlc4TK5ymFjmoFkKYvhvAH0GLwIc0G3y - o+LbCu436/2HIBmyIb/LF8S0OYyfZo52Dj8YJIiRhQCUBh8FRDBtDWPSEkJV7yrSnw22x+w0QZ2W8IAZ - Cphd4zCzFmaw7yshjP0LQv3bj6VNL1vFQzhsOnwQPh3hYvYowOkNQkcn6Kl06xH8YhA+RYilUNEUPXoP - uuZccNI7ZcjGSMwuEIhqtcRBAcb1XRioeZ5Kb41gjsKm6E3Gl6KQgT9+qOgdHN4QMl5p9wFZFGCnANPG - LpORykBhOks0CYPQJKN0HR5kpwCh7ADgWpWWbHuCMMTNkXgSHsLfZYquwyfRUm25Q0ivPAAQyjTERv83 - P3XPzAB0jb0Un9QdKGsVo6gxB/lvRLhaVrZ/xPRKDdlwBTBvicaOih6Tije39bXj5dd8dOtbMGtVokn1 - ELebzuKiNEHOAGnlY8TqJMjrDuBWN8HNHoJc+p2rCOBGF8GdWhE6dW/RaWgGX3K1BE3qYiRJj0XXSCkd - JmY7weORCD6bgI9GoM0AtNL+nvbs58no1X9g5r1SzLUgVZoABrhUOuQzre3slgxFUDwQhmSQQ+FgmKmA - vi8/OYl6ZQFqlGJmrukXH05wvkS9aHb53CaLM7Jo82Nxy4+FmGyeEBo7XiNXfgoNykI2me/8O36DCyX9 - 0sTCPnVykcqeWNRF4pJEdU6iIGfy73Gp0hMsdpL0eDjlQVqvQCAQ/AfGuMf6qMo93wAAAABJRU5ErkJg - gg== + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAALdSURBVDhPVZFJTFNRFIa70rVLVkZXRqNEg2J0Q4gFqSQk + IroiFmTSxgmHxCgJIApIASXBkGDUFQsNiZQh0BYI0BZQEKSlrYoMBQqUls7vtn0tv/fdlgIn+XPeXfzf + +c95IqHEL4akmXVjqiz52FZ61RhHO2GqF/o4yaobJZJareHik5F3x3O+HGCmvZXxSjNi8xC71e4KO3wB + OLy7snsEEZisHpQpLMiVm/2X7/YcjFmjdaVGa7NtecKjiyGML/EYt/AYW+ShXQhi6G8AvUYfAjzQZeZQ + 9m0Jt5oM3D5IWsUA5/YHMbkcxs9lnnYePxgkiOG5AJRGPwVEMGkNY3w1hKoeC1KfDbTF7DRBrY4IgCkK + mF7hMbUSZrDvSyFo/gWh/s1hYcPHVvESHhtOP8RPh/mYPQpw+YLQ0wkGKv1aBL8YREgRYilUNEW3wYvO + GTdc9E5plRoSs4tEkhodcVKAaW0bRmqepTJYI5ihsAl6k9GFKKT/DwcVvYPTF0LaS90uIIMCHBRgXt9m + MlEZKUy/Gk3CIDTJCF1HADkoQFy5B5BepSN2bxDGuDkSTyJAhLtM0HWEJDoqmyeE1PI9AHGllmzS/y1M + 3TEzAF1jJ8UndTsetUhR1JCFvDcSXCot3T1iarmWrLsDmF2Nxo6KHpNKMLf2tqHiax66DM2YtirRqLqD + G40ncU6WIGeAlMcaYnUR5HQFcL2L4Fo3QTb9zlYEcLWTILdGgg79W3QYmyCUXF2IRnUxEmWHomskPRgi + yw6Ce8MRfDYDH01AqxFoof097ZnPT6PH8IGZd0ox04xkWQIY4PzDQb9p2bFdMhhBcX8YhQM8CgbCTPn0 + feH+UdQp81GtlDJzdZ90f4IzJep5i9vvMa04I/ObHOZtHOZi2vSG0ND+GtnyY6hXFrDJQhfe8RsklfTJ + Egt61aeLVI7EIgWJqzCqU4Ud5IT0Jp8sO8JiJ8oOh8/eTukRiUSi/4nSx9TsbwYuAAAAAElFTkSuQmCC iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHGSURBVDhPjZLdSypBGIfnP6ztorqIPqikL6w10lQoSsqg - UokDZQchNnHdviwIyj7V5sKbir7ANessdFGEHQ4VNojH98xsI9Ixan/wzM27v+cdhkXVvXLN9PrNnjOU - xg6GlMbWhSs8ELjElsAZtviPsZli9WPMvkX/x7VynfBt3WMjmH3xBK+VwzYbpX0yhnmtHHblQqFgiBb3 - XqXAKqn6cDOhpn9uZ3Ku5V9kdIkSviUjoQwZDl6S4cUzyikxzyaJbS6uCWK4kdeZ4EoXeCPaWyD2SL5i - InJHvNEHrdezf8vrCHX6krqAbf4Om3RObLKqmdwxjdcRqhbDox1TR3hQuiDZ36+UF5J9Yjx/JPtMXnK5 - P/l8Xmt1R8uCUmwLqsaGG4epp6mIWnTKGXCEKME02KUU0H8D+gPnYJk/hT7/CdjnMQh9SjevM0FKF4yv - 3sBM9MEQXb7Dv7yOUI83qQvYZqOYJmPA6whVieEfJk9ccwSvwWha3ftlQSn2RZWPK1Nk0KPIDprmsZ1P - BPTBvkpJwtI4slUp6JlJvk8NRLAolQJBlJUOz5H+QG0TB9AytgtNrig0DG1CvXMD6uxrUGtdBUFUKLLy - D8zckTa1u8hlAAAAAElFTkSuQmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHESURBVDhPjZLdSyJRGIfPf1jTRbsXSx+0SVFYY6ymQtsH + NYGlEgubLkJM5ThR7gZBuX2pnQtv+i5wtNqBvShCoQ+wg7i+e850RGii5gfPuXnn97yHw6DGPqVp+tfl + ljeawx6GnMPOuXP8JXKGHZFj7AjtYzvFGcKYfYteZmw5nw6uX2Mr2IOpNK/VwzZbpdOXxLxWD7typVKx + RLu0ZRY4Zc0YrqW13I+NfGl06Q8ZUSnKFRlevCBf508pR5QDYv+eIa7ZlC6IsRZeZ4JzQxD4qT9Fkrfk + LaT4XxJI3Oh9/u0rXkeoO5gxBGzze7jkY+JSNN0mJXVeR6hRjI12Te3hQfmEFIqPlAdSKDDuTTyWSnfl + clnvkBJ1QS2uOU1nw9XdbNEXz1a9ygV4opSFHLjlLNB/AwYiJ+AIH0J/6ADcYQxCv9rD60yQNQQTK5cw + k7ixRHdw9x+vI9QbyBgCttkqNl8SeB2hBjH2zeZP6Z6FPFhNh7RdF9Tintf42Jwqgx5VdtC0jf9+RUAf + 7K3UJCwtI+tmQe9M5nlqIYJDNQsEUVG7/HvGA32e3IH28U1oHUvAp6E1+OhdhQ/uODQ7V0AQVYqi/gdI + 3JEA0ERwkQAAAABJRU5ErkJggg== \ No newline at end of file diff --git a/TemplateBuilder/Repopulator/CsvToDicomTagMapping.cs b/TemplateBuilder/Repopulator/CsvToDicomTagMapping.cs new file mode 100644 index 0000000..bd0fde2 --- /dev/null +++ b/TemplateBuilder/Repopulator/CsvToDicomTagMapping.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using CsvHelper; +using CsvHelper.Configuration; +using Dicom; +using DicomTypeTranslation; + +namespace TemplateBuilder.Repopulator +{ + class CsvToDicomTagMapping + { + public Dictionary Map = new Dictionary(StringComparer.CurrentCultureIgnoreCase); + + public bool BuildMap(RepopulatorUIState state, out string log) + { + Map.Clear(); + + StringBuilder sb = new StringBuilder(); + try + { + + using (var reader = new CsvReader(state.CsvFileInfo.OpenText())) + { + reader.Configuration.TrimOptions = TrimOptions.Trim; + reader.Read(); + var couldReadHeader = reader.ReadHeader(); + + sb.AppendLine("Could Read Header:" + couldReadHeader); + + if (couldReadHeader) + { + foreach (var header in reader.Context.HeaderRecord) + { + if (GetKeyDicomTagAndColumnName(header, out Tuple match)) + { + Map.Add(match.Item1,match.Item2); + sb.AppendLine($"Validated header ''{header}''"); + } + else + sb.AppendLine($"Could not determine tag for '{header}'"); + } + } + + sb.AppendLine($"Found {Map.Count} valid mappings"); + } + } + catch (Exception e) + { + sb.AppendLine(e.ToString()); + log = sb.ToString(); + return false; + } + + log = sb.ToString(); + return Map.Count > 0; + } + + /// + /// Get the key DicomTag and associated CSV column name. + /// + public static bool GetKeyDicomTagAndColumnName(string columnName, out Tuple match) + { + string[] split = columnName.Split(':'); + if (split.Length == 1) + { + var found = DicomDictionary.Default.SingleOrDefault(entry => string.Equals(entry.Keyword ,columnName,StringComparison.CurrentCultureIgnoreCase)); + + if (found != null) + { + match = Tuple.Create(columnName, found.Tag); + return true; + } + + match = default; + return false; + } + + if(split.Length != 2 || split[0].Length == 0 || split[1].Length == 0) + { + match = default; + return false; + } + string dicomTagString = split[1]; + + // Check the DICOM tag is a valid DICOM tag + DicomDictionaryEntry prasedDictEntry = + DicomDictionary.Default.SingleOrDefault(entry => string.Equals(entry.Keyword ,dicomTagString,StringComparison.CurrentCultureIgnoreCase)); + + if (prasedDictEntry == null) + { + match = default; + return false; + } + + match = Tuple.Create(columnName, prasedDictEntry.Tag); + return true; + } + } +} diff --git a/TemplateBuilder/Repopulator/DicomRepopulatorProcessor.cs b/TemplateBuilder/Repopulator/DicomRepopulatorProcessor.cs new file mode 100644 index 0000000..0d72beb --- /dev/null +++ b/TemplateBuilder/Repopulator/DicomRepopulatorProcessor.cs @@ -0,0 +1,194 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using CsvHelper; +using CsvHelper.Configuration; +using Dicom; +using DicomTypeTranslation.Helpers; +using NLog; + +namespace TemplateBuilder.Repopulator +{ + public class DicomRepopulatorProcessor + { + private readonly ILogger _logger; + + private int _nInput; + private int _nMatched; + private int _nProcessed; + + private Stopwatch _stopwatch; + + private ParallelOptions _parallelOptions; + + + public DicomRepopulatorProcessor(string currentDirectory = null) + { + LogManager.Configuration = new NLog.Config.XmlLoggingConfiguration(Path.Combine(currentDirectory ?? Environment.CurrentDirectory, "Microservices.NLog.config"), false); + _logger = LogManager.GetCurrentClassLogger(); + + if (!DicomDatasetHelpers.CorrectFoDicomVersion()) + throw new ApplicationException("Incorrect fo-dicom version for the current platform"); + } + + + public int Process(RepopulatorUIState options) + { + _parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = options.NumThreads }; + + _logger.Debug("CLI options:\n" + options); + + _logger.Debug("Checking output directory for contents"); + if (options.OutputDirectoryInfo.EnumerateFileSystemInfos().Any()) + { + _logger.Error("Output directory " + options.OutputDirectoryInfo.FullName + " is not empty"); + return -1; + } + + Dictionary keyDicomTagToColumnIndexMapping; + Dictionary replacementDict; + + _logger.Info("Starting to process"); + _stopwatch = Stopwatch.StartNew(); + + var map = new CsvToDicomTagMapping(); + + try + { + if(!map.BuildMap(options,out _)) + throw new Exception("Failed to build map"); + } + catch (ApplicationException e) + { + _logger.Error("Exception processing csv file: " + e.Message); + return -1; + } + + _logger.Info("Loaded " + map.Map.Count + " rows from " + options.CsvFileInfo.FullName); + + try + { + ProcessDicomFiles(options, map.Map); + } + catch (Exception e) + { + _logger.Error("Exception processing dicom files: " + e.Message); + return -1; + } + + var sb = new StringBuilder(); + sb.AppendLine("\n=== Finished processing ==="); + sb.AppendLine("Total input files: " + _nInput); + sb.AppendLine("Total matched to input data: " + _nMatched); + sb.Append("Total processed: " + _nProcessed); + + _logger.Info(sb.ToString()); + + _logger.Info("Duration = " + _stopwatch.ElapsedMilliseconds / 1000.0 + "s"); + + return 0; + } + + + /// + /// Processes the Dicom files and alters the values according to the replacement dictionary. + /// Makes an alternate copy of each Dicom file into the output directory. + /// + /// Options as specified on the command line. + /// contains new values for the tags to be altered. + private void ProcessDicomFiles( + RepopulatorUIState options, + Dictionary map) + { + _logger.Info("Starting directory scan of " + options.DirectoryToProcessInfo.FullName); + + var dirStack = new Stack(); + dirStack.Push(options.DirectoryToProcessInfo); + + while (dirStack.Count > 0) + { + DirectoryInfo dir = dirStack.Pop(); + _logger.Info("Processing directory " + dir.FullName); + + if (!dir.Exists) + throw new ApplicationException("A previously seen directory can no longer be found: " + dir); + + /*Parallel.ForEach( + dir.EnumerateFiles("*.dcm"), + _parallelOptions, + currentFile => ProcessDicomFile(currentFile, keyDicomTagToColumnIndexMapping, replacementDict, options));*/ + + DirectoryInfo[] subDirs = dir.GetDirectories(); + for (int i = subDirs.Length - 1; i >= 0; i--) + { + _logger.Debug("Found subdirectory " + subDirs[i].FullName); + dirStack.Push(subDirs[i]); + + string relativeDir = subDirs[i].FullName.Replace(options.DirectoryToProcessInfo.FullName + Path.DirectorySeparatorChar, ""); + Directory.CreateDirectory(Path.Combine(options.OutputDirectoryInfo.FullName, relativeDir)); + } + } + } + + /// + /// Processes a single Dicom file applying the required alterations as specified in the replacement dictionary. + /// + /// File to be processed. + /// DicomTag specifying the key and the corresponding column index in the CSV file. + /// Replacement dictionary that maps Series Ids to a Dicom data set that contains new values for the + /// tags to be altered. + /// Command line options. + private void ProcessDicomFile( + FileSystemInfo dFilePath, + Dictionary keyDicomTagToColumnIndexMapping, + Dictionary replacementDict, + RepopulatorUIState options) + { + _logger.Debug("Processing file " + dFilePath.FullName); + + Interlocked.Increment(ref _nInput); + + DicomFile dFile = DicomFile.Open(dFilePath.FullName); + string inputRelativePath = dFilePath.FullName.Replace(options.DirectoryToProcessInfo.FullName, "").TrimStart(Path.DirectorySeparatorChar); + + string key; + + try + { + DicomTag keyDicomTag = keyDicomTagToColumnIndexMapping.Keys.First(); + string keyTagName = keyDicomTag.DictionaryEntry.Keyword; + + key = dFile.Dataset.GetValue(keyDicomTag, 0); + + if (!replacementDict.ContainsKey(key)) + { + _logger.Warn("No replacement data loaded for file " + inputRelativePath + " with " + keyTagName + "=" + key); + return; + } + + _logger.Debug("Matched file " + keyTagName + "=" + key + " with row from csv data"); + Interlocked.Increment(ref _nMatched); + } + catch (DicomDataException e) + { + _logger.Error("Exception reading data from file " + inputRelativePath + e.Message); + return; + } + + _logger.Debug("Updating file dataset"); + dFile.Dataset.AddOrUpdate(replacementDict[key]); + + _logger.Debug("Saving output file"); + + // Preserves any sub-directory structures + dFile.Save(Path.Combine(options.OutputDirectoryInfo.FullName, inputRelativePath)); + + Interlocked.Increment(ref _nProcessed); + } + } +} diff --git a/TemplateBuilder/Repopulator/RepopulatorUI.Designer.cs b/TemplateBuilder/Repopulator/RepopulatorUI.Designer.cs new file mode 100644 index 0000000..4a0edb4 --- /dev/null +++ b/TemplateBuilder/Repopulator/RepopulatorUI.Designer.cs @@ -0,0 +1,300 @@ +namespace TemplateBuilder.Repopulator +{ + partial class RepopulatorUI + { + /// + /// 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 Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnInputFolder = new System.Windows.Forms.Button(); + this.btnOutputFolder = new System.Windows.Forms.Button(); + this.cbIncludeSubfolders = new System.Windows.Forms.CheckBox(); + this.tbPattern = new System.Windows.Forms.TextBox(); + this.tbInputFolder = new System.Windows.Forms.TextBox(); + this.label1 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.tbOutputFolder = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.nThreads = new System.Windows.Forms.NumericUpDown(); + this.label4 = new System.Windows.Forms.Label(); + this.progressBar1 = new System.Windows.Forms.ProgressBar(); + this.lblProgress = new System.Windows.Forms.Label(); + this.btnStart = new System.Windows.Forms.Button(); + this.tbInputCsv = new System.Windows.Forms.TextBox(); + this.label5 = new System.Windows.Forms.Label(); + this.btnInputCsv = new System.Windows.Forms.Button(); + this.btnValidateCsv = new System.Windows.Forms.Button(); + ((System.ComponentModel.ISupportInitialize)(this.nThreads)).BeginInit(); + this.SuspendLayout(); + // + // btnInputFolder + // + this.btnInputFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnInputFolder.Location = new System.Drawing.Point(496, 28); + this.btnInputFolder.Name = "btnInputFolder"; + this.btnInputFolder.Size = new System.Drawing.Size(67, 23); + this.btnInputFolder.TabIndex = 1; + this.btnInputFolder.Text = "Browse..."; + this.btnInputFolder.UseVisualStyleBackColor = true; + this.btnInputFolder.Click += new System.EventHandler(this.btnBrowse_Click); + // + // btnOutputFolder + // + this.btnOutputFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnOutputFolder.Location = new System.Drawing.Point(496, 121); + this.btnOutputFolder.Name = "btnOutputFolder"; + this.btnOutputFolder.Size = new System.Drawing.Size(67, 23); + this.btnOutputFolder.TabIndex = 10; + this.btnOutputFolder.Text = "Browse"; + this.btnOutputFolder.UseVisualStyleBackColor = true; + this.btnOutputFolder.Click += new System.EventHandler(this.btnBrowse_Click); + // + // cbIncludeSubfolders + // + this.cbIncludeSubfolders.AutoSize = true; + this.cbIncludeSubfolders.Checked = true; + this.cbIncludeSubfolders.CheckState = System.Windows.Forms.CheckState.Checked; + this.cbIncludeSubfolders.Location = new System.Drawing.Point(96, 56); + this.cbIncludeSubfolders.Name = "cbIncludeSubfolders"; + this.cbIncludeSubfolders.Size = new System.Drawing.Size(120, 17); + this.cbIncludeSubfolders.TabIndex = 2; + this.cbIncludeSubfolders.Text = "Include Sub Folders"; + this.cbIncludeSubfolders.UseVisualStyleBackColor = true; + this.cbIncludeSubfolders.CheckedChanged += new System.EventHandler(this.cbIncludeSubfolders_CheckedChanged); + // + // tbPattern + // + this.tbPattern.Location = new System.Drawing.Point(291, 56); + this.tbPattern.Name = "tbPattern"; + this.tbPattern.Size = new System.Drawing.Size(100, 20); + this.tbPattern.TabIndex = 4; + this.tbPattern.Text = "*.dcm"; + this.tbPattern.TextChanged += new System.EventHandler(this.tbPattern_TextChanged); + // + // tbInputFolder + // + this.tbInputFolder.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.tbInputFolder.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.Suggest; + this.tbInputFolder.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.FileSystem; + this.tbInputFolder.Location = new System.Drawing.Point(88, 30); + this.tbInputFolder.Name = "tbInputFolder"; + this.tbInputFolder.Size = new System.Drawing.Size(402, 20); + this.tbInputFolder.TabIndex = 0; + this.tbInputFolder.TextChanged += new System.EventHandler(this.tb_TextChanged); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(10, 33); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(66, 13); + this.label1.TabIndex = 4; + this.label1.Text = "Input Folder:"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(10, 126); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(74, 13); + this.label3.TabIndex = 4; + this.label3.Text = "Output Folder:"; + // + // tbOutputFolder + // + this.tbOutputFolder.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.tbOutputFolder.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.Suggest; + this.tbOutputFolder.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.FileSystem; + this.tbOutputFolder.Location = new System.Drawing.Point(88, 123); + this.tbOutputFolder.Name = "tbOutputFolder"; + this.tbOutputFolder.Size = new System.Drawing.Size(402, 20); + this.tbOutputFolder.TabIndex = 9; + this.tbOutputFolder.TextChanged += new System.EventHandler(this.tb_TextChanged); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(222, 59); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(63, 13); + this.label2.TabIndex = 3; + this.label2.Text = "File Pattern:"; + // + // nThreads + // + this.nThreads.Location = new System.Drawing.Point(452, 57); + this.nThreads.Maximum = new decimal(new int[] { + 10, + 0, + 0, + 0}); + this.nThreads.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.nThreads.Name = "nThreads"; + this.nThreads.Size = new System.Drawing.Size(111, 20); + this.nThreads.TabIndex = 6; + this.nThreads.Value = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.nThreads.ValueChanged += new System.EventHandler(this.nThreads_ValueChanged); + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(397, 59); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(49, 13); + this.label4.TabIndex = 5; + this.label4.Text = "Threads:"; + // + // progressBar1 + // + this.progressBar1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.progressBar1.Location = new System.Drawing.Point(8, 178); + this.progressBar1.Name = "progressBar1"; + this.progressBar1.Size = new System.Drawing.Size(556, 10); + this.progressBar1.TabIndex = 8; + // + // lblProgress + // + this.lblProgress.AutoSize = true; + this.lblProgress.Location = new System.Drawing.Point(10, 194); + this.lblProgress.Name = "lblProgress"; + this.lblProgress.Size = new System.Drawing.Size(58, 13); + this.lblProgress.TabIndex = 9; + this.lblProgress.Text = "lblProgress"; + // + // btnStart + // + this.btnStart.Location = new System.Drawing.Point(218, 149); + this.btnStart.Name = "btnStart"; + this.btnStart.Size = new System.Drawing.Size(67, 23); + this.btnStart.TabIndex = 11; + this.btnStart.Text = "Start"; + this.btnStart.UseVisualStyleBackColor = true; + this.btnStart.Click += new System.EventHandler(this.btnStart_Click); + // + // tbInputCsv + // + this.tbInputCsv.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.tbInputCsv.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.Suggest; + this.tbInputCsv.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.FileSystem; + this.tbInputCsv.Location = new System.Drawing.Point(88, 95); + this.tbInputCsv.Name = "tbInputCsv"; + this.tbInputCsv.Size = new System.Drawing.Size(402, 20); + this.tbInputCsv.TabIndex = 7; + this.tbInputCsv.TextChanged += new System.EventHandler(this.tb_TextChanged); + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(10, 98); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(55, 13); + this.label5.TabIndex = 4; + this.label5.Text = "Input Csv:"; + // + // btnInputCsv + // + this.btnInputCsv.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnInputCsv.Location = new System.Drawing.Point(496, 93); + this.btnInputCsv.Name = "btnInputCsv"; + this.btnInputCsv.Size = new System.Drawing.Size(67, 23); + this.btnInputCsv.TabIndex = 8; + this.btnInputCsv.Text = "Browse..."; + this.btnInputCsv.UseVisualStyleBackColor = true; + this.btnInputCsv.Click += new System.EventHandler(this.btnBrowse_Click); + // + // btnValidateCsv + // + this.btnValidateCsv.Location = new System.Drawing.Point(88, 149); + this.btnValidateCsv.Name = "btnValidateCsv"; + this.btnValidateCsv.Size = new System.Drawing.Size(125, 23); + this.btnValidateCsv.TabIndex = 11; + this.btnValidateCsv.Text = "Validate Csv Headers"; + this.btnValidateCsv.UseVisualStyleBackColor = true; + this.btnValidateCsv.Click += new System.EventHandler(this.btnValidateCsv_Click); + // + // RepopulatorUI + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.btnInputCsv); + this.Controls.Add(this.lblProgress); + this.Controls.Add(this.progressBar1); + this.Controls.Add(this.nThreads); + this.Controls.Add(this.label4); + this.Controls.Add(this.label2); + this.Controls.Add(this.label5); + this.Controls.Add(this.label3); + this.Controls.Add(this.label1); + this.Controls.Add(this.tbOutputFolder); + this.Controls.Add(this.tbInputCsv); + this.Controls.Add(this.tbInputFolder); + this.Controls.Add(this.tbPattern); + this.Controls.Add(this.cbIncludeSubfolders); + this.Controls.Add(this.btnValidateCsv); + this.Controls.Add(this.btnStart); + this.Controls.Add(this.btnOutputFolder); + this.Controls.Add(this.btnInputFolder); + this.Name = "RepopulatorUI"; + this.Size = new System.Drawing.Size(575, 214); + ((System.ComponentModel.ISupportInitialize)(this.nThreads)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button btnInputFolder; + private System.Windows.Forms.Button btnOutputFolder; + private System.Windows.Forms.CheckBox cbIncludeSubfolders; + private System.Windows.Forms.TextBox tbPattern; + private System.Windows.Forms.TextBox tbInputFolder; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.TextBox tbOutputFolder; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.NumericUpDown nThreads; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.ProgressBar progressBar1; + private System.Windows.Forms.Label lblProgress; + private System.Windows.Forms.Button btnStart; + private System.Windows.Forms.TextBox tbInputCsv; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.Button btnInputCsv; + private System.Windows.Forms.Button btnValidateCsv; + } +} diff --git a/TemplateBuilder/Repopulator/RepopulatorUI.cs b/TemplateBuilder/Repopulator/RepopulatorUI.cs new file mode 100644 index 0000000..140ba7d --- /dev/null +++ b/TemplateBuilder/Repopulator/RepopulatorUI.cs @@ -0,0 +1,121 @@ +using System; +using System.IO; +using System.Windows.Forms; +using YamlDotNet.Serialization; + +namespace TemplateBuilder.Repopulator +{ + public partial class RepopulatorUI : UserControl + { + public RepopulatorUIState State; + private const string StateFile = "RepopulatorUI.yaml"; + public RepopulatorUI() + { + InitializeComponent(); + + State = new RepopulatorUIState(); + + try + { + if (File.Exists("RepopulatorUI.yaml")) + { + var des = new Deserializer(); + State = des.Deserialize(File.ReadAllText(StateFile)); + + cbIncludeSubfolders.Checked = State.IncludeSubdirectories; + tbInputFolder.Text = State.InputFolder; + tbInputCsv.Text = State.InputCsv; + tbOutputFolder.Text = State.OutputFolder; + nThreads.Value = State.NumThreads; + tbPattern.Text = State.Pattern; + } + } + catch (Exception) + { + } + + } + + private void btnBrowse_Click(object sender, EventArgs e) + { + if (sender == btnInputCsv) + { + var ofd = new OpenFileDialog(); + ofd.CheckPathExists = true; + ofd.Filter = "Comma Separated File|*.csv"; + ofd.Multiselect = false; + + if(ofd.ShowDialog()==DialogResult.OK) + tbInputCsv.Text = ofd.FileName; + } + else + { + var ofd = new FolderBrowserDialog(); + if (ofd.ShowDialog() == DialogResult.OK) + { + var tb = sender == btnInputFolder ? tbInputFolder : tbOutputFolder; + tb.Text = ofd.SelectedPath; + } + } + } + + private void btnStart_Click(object sender, EventArgs e) + { + + } + + private void tb_TextChanged(object sender, EventArgs e) + { + if(sender == tbInputFolder) + State.InputFolder = tbInputFolder.Text; + + if(sender == tbInputCsv) + State.InputCsv = tbInputCsv.Text; + + if(sender == tbOutputFolder) + State.OutputFolder = tbOutputFolder.Text; + + + SaveState(); + } + + private void SaveState() + { + try + { + var ser = new Serializer(); + File.WriteAllText(StateFile,ser.Serialize(State)); + } + catch (Exception) + { + + } + } + + private void cbIncludeSubfolders_CheckedChanged(object sender, EventArgs e) + { + State.IncludeSubdirectories = cbIncludeSubfolders.Checked; + SaveState(); + } + + private void tbPattern_TextChanged(object sender, EventArgs e) + { + State.Pattern = tbPattern.Text; + SaveState(); + } + + private void nThreads_ValueChanged(object sender, EventArgs e) + { + State.NumThreads = (int) nThreads.Value; + SaveState(); + } + + private void btnValidateCsv_Click(object sender, EventArgs e) + { + var mapping = new CsvToDicomTagMapping(); + bool built = mapping.BuildMap(State, out string log); + + MessageBox.Show(log,$"Validation { (built ? "Success" : "Failure" )}",MessageBoxButtons.OK,built ? MessageBoxIcon.Information: MessageBoxIcon.Error); + } + } +} diff --git a/TemplateBuilder/Repopulator/RepopulatorUI.resx b/TemplateBuilder/Repopulator/RepopulatorUI.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/TemplateBuilder/Repopulator/RepopulatorUI.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + \ No newline at end of file diff --git a/TemplateBuilder/Repopulator/RepopulatorUIState.cs b/TemplateBuilder/Repopulator/RepopulatorUIState.cs new file mode 100644 index 0000000..5bf0aa3 --- /dev/null +++ b/TemplateBuilder/Repopulator/RepopulatorUIState.cs @@ -0,0 +1,20 @@ +using System.IO; +using System.Windows.Input; + +namespace TemplateBuilder.Repopulator +{ + public class RepopulatorUIState + { + public string InputFolder; + public string InputCsv; + public string OutputFolder; + public int NumThreads; + public bool IncludeSubdirectories; + public string Pattern; + + public DirectoryInfo OutputDirectoryInfo => new DirectoryInfo(OutputFolder); + public DirectoryInfo DirectoryToProcessInfo => new DirectoryInfo(InputFolder); + + public FileInfo CsvFileInfo => new FileInfo(InputCsv); + } +} \ No newline at end of file diff --git a/TemplateBuilder/RepopulatorUI.resx b/TemplateBuilder/RepopulatorUI.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/TemplateBuilder/RepopulatorUI.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + \ No newline at end of file diff --git a/TemplateBuilder/TemplateBuilder.csproj b/TemplateBuilder/TemplateBuilder.csproj index 54ed48f..e272ede 100644 --- a/TemplateBuilder/TemplateBuilder.csproj +++ b/TemplateBuilder/TemplateBuilder.csproj @@ -58,6 +58,7 @@ Settings.Designer.cs + From 55193e9ebd3b4afbefeb2e099e5ff0b8a5e56ab2 Mon Sep 17 00:00:00 2001 From: Thomas Nind Date: Wed, 23 Oct 2019 14:26:41 +0100 Subject: [PATCH 02/19] Fixed yaml serialization of last used values --- TemplateBuilder/Repopulator/RepopulatorUI.cs | 2 +- TemplateBuilder/Repopulator/RepopulatorUIState.cs | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/TemplateBuilder/Repopulator/RepopulatorUI.cs b/TemplateBuilder/Repopulator/RepopulatorUI.cs index 140ba7d..b1b80d6 100644 --- a/TemplateBuilder/Repopulator/RepopulatorUI.cs +++ b/TemplateBuilder/Repopulator/RepopulatorUI.cs @@ -26,7 +26,7 @@ public RepopulatorUI() tbInputFolder.Text = State.InputFolder; tbInputCsv.Text = State.InputCsv; tbOutputFolder.Text = State.OutputFolder; - nThreads.Value = State.NumThreads; + nThreads.Value = Math.Min(Math.Max(nThreads.Minimum,State.NumThreads),nThreads.Maximum); tbPattern.Text = State.Pattern; } } diff --git a/TemplateBuilder/Repopulator/RepopulatorUIState.cs b/TemplateBuilder/Repopulator/RepopulatorUIState.cs index 5bf0aa3..67dd809 100644 --- a/TemplateBuilder/Repopulator/RepopulatorUIState.cs +++ b/TemplateBuilder/Repopulator/RepopulatorUIState.cs @@ -1,5 +1,6 @@ using System.IO; using System.Windows.Input; +using YamlDotNet.Serialization; namespace TemplateBuilder.Repopulator { @@ -12,9 +13,13 @@ public class RepopulatorUIState public bool IncludeSubdirectories; public string Pattern; + [YamlIgnore] public DirectoryInfo OutputDirectoryInfo => new DirectoryInfo(OutputFolder); + + [YamlIgnore] public DirectoryInfo DirectoryToProcessInfo => new DirectoryInfo(InputFolder); - + + [YamlIgnore] public FileInfo CsvFileInfo => new FileInfo(InputCsv); } } \ No newline at end of file From 9277cf088b9756d53d6d4ae98e656b74a073a68a Mon Sep 17 00:00:00 2001 From: Thomas Nind Date: Fri, 25 Oct 2019 09:07:06 +0100 Subject: [PATCH 03/19] Added file path column and anonymise option. Added output UI elements for tracking progress. --- TemplateBuilder/Form1.Designer.cs | 16 +-- TemplateBuilder/Form1.resx | 120 ++++++++--------- .../Repopulator/CsvToDicomTagMapping.cs | 111 +++++++++++----- .../Repopulator/DicomRepopulatorProcessor.cs | 33 +++-- .../Repopulator/RepopulatorUI.Designer.cs | 123 ++++++++++++++---- TemplateBuilder/Repopulator/RepopulatorUI.cs | 53 +++++++- .../Repopulator/RepopulatorUI.resx | 3 + .../Repopulator/RepopulatorUIState.cs | 5 + 8 files changed, 326 insertions(+), 138 deletions(-) diff --git a/TemplateBuilder/Form1.Designer.cs b/TemplateBuilder/Form1.Designer.cs index 085c89a..ba2ee8b 100644 --- a/TemplateBuilder/Form1.Designer.cs +++ b/TemplateBuilder/Form1.Designer.cs @@ -51,8 +51,8 @@ private void InitializeComponent() this.miWindowSql = new System.Windows.Forms.ToolStripMenuItem(); this.miWindowFiles = new System.Windows.Forms.ToolStripMenuItem(); this.miWindowTable = new System.Windows.Forms.ToolStripMenuItem(); - this.dockPanel1 = new WeifenLuo.WinFormsUI.Docking.DockPanel(); this.tagPopulatorToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.dockPanel1 = new WeifenLuo.WinFormsUI.Docking.DockPanel(); ((System.ComponentModel.ISupportInitialize)(this.olvDicoms)).BeginInit(); this.toolStrip1.SuspendLayout(); this.SuspendLayout(); @@ -246,13 +246,6 @@ private void InitializeComponent() this.miWindowTable.Text = "Table Viewer"; this.miWindowTable.Click += new System.EventHandler(this.WindowClicked); // - // dockPanel1 - // - this.dockPanel1.Location = new System.Drawing.Point(12, 28); - this.dockPanel1.Name = "dockPanel1"; - this.dockPanel1.Size = new System.Drawing.Size(200, 100); - this.dockPanel1.TabIndex = 11; - // // tagPopulatorToolStripMenuItem // this.tagPopulatorToolStripMenuItem.Name = "tagPopulatorToolStripMenuItem"; @@ -260,6 +253,13 @@ private void InitializeComponent() this.tagPopulatorToolStripMenuItem.Text = "Tag Populator"; this.tagPopulatorToolStripMenuItem.Click += new System.EventHandler(this.tagPopulatorToolStripMenuItem_Click); // + // dockPanel1 + // + this.dockPanel1.Location = new System.Drawing.Point(12, 28); + this.dockPanel1.Name = "dockPanel1"; + this.dockPanel1.Size = new System.Drawing.Size(200, 100); + this.dockPanel1.TabIndex = 11; + // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); diff --git a/TemplateBuilder/Form1.resx b/TemplateBuilder/Form1.resx index a4449ab..388a4c7 100644 --- a/TemplateBuilder/Form1.resx +++ b/TemplateBuilder/Form1.resx @@ -144,55 +144,54 @@ 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 - gg== + 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 AABJRU5ErkJggg== @@ -216,33 +215,34 @@ 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 + gg== iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHESURBVDhPjZLdSyJRGIfPf1jTRbsXSx+0SVFYY6ymQtsH - NYGlEgubLkJM5ThR7gZBuX2pnQtv+i5wtNqBvShCoQ+wg7i+e850RGii5gfPuXnn97yHw6DGPqVp+tfl - ljeawx6GnMPOuXP8JXKGHZFj7AjtYzvFGcKYfYteZmw5nw6uX2Mr2IOpNK/VwzZbpdOXxLxWD7typVKx - RLu0ZRY4Zc0YrqW13I+NfGl06Q8ZUSnKFRlevCBf508pR5QDYv+eIa7ZlC6IsRZeZ4JzQxD4qT9Fkrfk - LaT4XxJI3Oh9/u0rXkeoO5gxBGzze7jkY+JSNN0mJXVeR6hRjI12Te3hQfmEFIqPlAdSKDDuTTyWSnfl - clnvkBJ1QS2uOU1nw9XdbNEXz1a9ygV4opSFHLjlLNB/AwYiJ+AIH0J/6ADcYQxCv9rD60yQNQQTK5cw - k7ixRHdw9x+vI9QbyBgCttkqNl8SeB2hBjH2zeZP6Z6FPFhNh7RdF9Tintf42Jwqgx5VdtC0jf9+RUAf - 7K3UJCwtI+tmQe9M5nlqIYJDNQsEUVG7/HvGA32e3IH28U1oHUvAp6E1+OhdhQ/uODQ7V0AQVYqi/gdI - 3JEA0ERwkQAAAABJRU5ErkJggg== + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAG/SURBVDhPjZLdSypBGIfnP6ztorqIOlGJUVhrHE2FPikP + 1VGJoCyE2MR1IfuAoOxTbS686fTBieNuXwtdFFHQKbBBzLeZbURoo/YHz9y8+3veYVhU3SXX/F652PbF + NOxlSBp2zZ/in5G/2Bk5xs7wAXZQXGGM2bfoY4YXzzKh9RtsBUconeG1Sthmq7SNpzCvVcKuXCwWLdHs + 3zYLXJJqDNcyqja3oeUHlSsyEKfELkl/9Jz0L5xQDikHxDGdJe6ZtC6I8UZeZ4JTQxBc1l8iqTvyFaOJ + axJM3updgZ1LXkeoPZQ1BGzzd7ilI+KWVd3mT+m8jlC1GB+yT+zjXumY3N8/Uf5zHk085/OPhUJBb/En + K4Jy3POqzoare7mHscS/kk8+B2+MEtXAI+WA/hvQEzkB5+whdIf/gGcWg9CtdPA6E+QMwWjiAiaTt5aw + h/ZeeR2hzmDWELDNVrGNp4DXEaoS41O2QFr3Rs/Aalr8OxVBOZ4FlY/NKTHoUWIHzY+RzU8E9MG+SlnC + 0ji4bhZ0TmbfpxYiOBWzQBBlxR7YNx6o9dcuNI9sQdNwEhr61qDetwp1niWodSVAEBWKrLwB0o6Q0BOi + V9gAAAAASUVORK5CYII= \ No newline at end of file diff --git a/TemplateBuilder/Repopulator/CsvToDicomTagMapping.cs b/TemplateBuilder/Repopulator/CsvToDicomTagMapping.cs index bd0fde2..d167065 100644 --- a/TemplateBuilder/Repopulator/CsvToDicomTagMapping.cs +++ b/TemplateBuilder/Repopulator/CsvToDicomTagMapping.cs @@ -14,16 +14,63 @@ namespace TemplateBuilder.Repopulator { class CsvToDicomTagMapping { - public Dictionary Map = new Dictionary(StringComparer.CurrentCultureIgnoreCase); + public class CsvToDicomColumn + { + public string Name { get; } + public int Index { get; } + public DicomTag MappedTag { get; } + public bool IsFilePath { get; set; } + + public CsvToDicomColumn(string colName, int index, DicomTag mappedTag, bool isFileColumn) + { + if (mappedTag != null && isFileColumn) + throw new ArgumentException("Column should either be a dicom tag or a file path column not both"); + + if (mappedTag == null && !isFileColumn) + throw new ArgumentException("Column must either contain dicom tags or be a file path column"); + + Name = colName; + Index = index; + MappedTag = mappedTag; + IsFilePath = isFileColumn; + } + } + + /// + /// The column of the CSV which records the file path to the image(s) being processed. These should be expressed + /// relatively (i.e. not absolute path names) + /// + public CsvToDicomColumn FilenameColumn; + + /// + /// Columns which contain dicom tag values. This is not all the columns in the CSV. It does not include + /// or any columns which could not be mapped; + /// + public List TagColumns = new List(); + /// + /// Clears current column mappings + /// + public void Clear() + { + FilenameColumn = null; + TagColumns.Clear(); + } + + /// + /// Reads the headers from the CSV specified in and builds and . + /// Returns true if the headers constitute a valid set (at least 1 and found). + /// + /// + /// + /// public bool BuildMap(RepopulatorUIState state, out string log) { - Map.Clear(); + Clear(); StringBuilder sb = new StringBuilder(); try { - using (var reader = new CsvReader(state.CsvFileInfo.OpenText())) { reader.Configuration.TrimOptions = TrimOptions.Trim; @@ -34,11 +81,26 @@ public bool BuildMap(RepopulatorUIState state, out string log) if (couldReadHeader) { - foreach (var header in reader.Context.HeaderRecord) + for (var index = 0; index < reader.Context.HeaderRecord.Length; index++) { - if (GetKeyDicomTagAndColumnName(header, out Tuple match)) + var header = reader.Context.HeaderRecord[index]; + var match = GetKeyDicomTagAndColumnName(state, header, index); + + if (match != null) { - Map.Add(match.Item1,match.Item2); + if(match.IsFilePath) + if (FilenameColumn != null) + throw new Exception("There are 2+ FilenameColumn in the CSV"); + else + FilenameColumn = match; + else + { + if(TagColumns.Any(c=>c.MappedTag == match.MappedTag)) + throw new Exception($"There are 2+ columns that both contain DicomTag '{match.MappedTag}'"); + + TagColumns.Add(match); + } + sb.AppendLine($"Validated header ''{header}''"); } else @@ -46,7 +108,8 @@ public bool BuildMap(RepopulatorUIState state, out string log) } } - sb.AppendLine($"Found {Map.Count} valid mappings"); + sb.AppendLine($"Found {TagColumns.Count} valid mappings"); + sb.AppendLine($"FilenameColumn is: {FilenameColumn?.Name ?? "Not Set"}"); } } catch (Exception e) @@ -57,48 +120,34 @@ public bool BuildMap(RepopulatorUIState state, out string log) } log = sb.ToString(); - return Map.Count > 0; + return TagColumns.Count > 0 && FilenameColumn != null; } /// /// Get the key DicomTag and associated CSV column name. /// - public static bool GetKeyDicomTagAndColumnName(string columnName, out Tuple match) + public CsvToDicomColumn GetKeyDicomTagAndColumnName(RepopulatorUIState state, string columnName,int index) { + if(columnName.Equals(state.FileNameColumn,StringComparison.CurrentCultureIgnoreCase)) + return new CsvToDicomColumn(columnName,index,null,true); + string[] split = columnName.Split(':'); if (split.Length == 1) { var found = DicomDictionary.Default.SingleOrDefault(entry => string.Equals(entry.Keyword ,columnName,StringComparison.CurrentCultureIgnoreCase)); - - if (found != null) - { - match = Tuple.Create(columnName, found.Tag); - return true; - } - - match = default; - return false; + return found != null ? new CsvToDicomColumn(columnName,index,found.Tag,false) : null; } if(split.Length != 2 || split[0].Length == 0 || split[1].Length == 0) - { - match = default; - return false; - } + return null; + string dicomTagString = split[1]; // Check the DICOM tag is a valid DICOM tag - DicomDictionaryEntry prasedDictEntry = + var found2 = DicomDictionary.Default.SingleOrDefault(entry => string.Equals(entry.Keyword ,dicomTagString,StringComparison.CurrentCultureIgnoreCase)); - if (prasedDictEntry == null) - { - match = default; - return false; - } - - match = Tuple.Create(columnName, prasedDictEntry.Tag); - return true; + return found2 != null ? new CsvToDicomColumn(columnName, index, found2.Tag, false) : null; } } } diff --git a/TemplateBuilder/Repopulator/DicomRepopulatorProcessor.cs b/TemplateBuilder/Repopulator/DicomRepopulatorProcessor.cs index 0d72beb..e53f1f0 100644 --- a/TemplateBuilder/Repopulator/DicomRepopulatorProcessor.cs +++ b/TemplateBuilder/Repopulator/DicomRepopulatorProcessor.cs @@ -11,6 +11,7 @@ using Dicom; using DicomTypeTranslation.Helpers; using NLog; +using NLog.Targets; namespace TemplateBuilder.Repopulator { @@ -26,33 +27,40 @@ public class DicomRepopulatorProcessor private ParallelOptions _parallelOptions; - + public MemoryTarget MemoryLogTarget { get; } = new MemoryTarget(); + public int Done { get; private set; } + public DicomRepopulatorProcessor(string currentDirectory = null) { - LogManager.Configuration = new NLog.Config.XmlLoggingConfiguration(Path.Combine(currentDirectory ?? Environment.CurrentDirectory, "Microservices.NLog.config"), false); + string log = Path.Combine(currentDirectory ?? Environment.CurrentDirectory, "NLog.config"); + + if(File.Exists(log)) + LogManager.Configuration = new NLog.Config.XmlLoggingConfiguration(log, false); + + LogManager.Configuration.AddTarget(MemoryLogTarget); + _logger = LogManager.GetCurrentClassLogger(); if (!DicomDatasetHelpers.CorrectFoDicomVersion()) throw new ApplicationException("Incorrect fo-dicom version for the current platform"); + + MemoryLogTarget.Layout = "${level} ${message}"; } + + public int Process(RepopulatorUIState options) { _parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = options.NumThreads }; - - _logger.Debug("CLI options:\n" + options); - + _logger.Debug("Checking output directory for contents"); if (options.OutputDirectoryInfo.EnumerateFileSystemInfos().Any()) { _logger.Error("Output directory " + options.OutputDirectoryInfo.FullName + " is not empty"); return -1; } - - Dictionary keyDicomTagToColumnIndexMapping; - Dictionary replacementDict; - + _logger.Info("Starting to process"); _stopwatch = Stopwatch.StartNew(); @@ -69,11 +77,12 @@ public int Process(RepopulatorUIState options) return -1; } - _logger.Info("Loaded " + map.Map.Count + " rows from " + options.CsvFileInfo.FullName); + _logger.Info("Loaded " + map.TagColumns.Count + " rows from " + options.CsvFileInfo.FullName); + try { - ProcessDicomFiles(options, map.Map); + ProcessDicomFiles(options, map); } catch (Exception e) { @@ -103,7 +112,7 @@ public int Process(RepopulatorUIState options) /// contains new values for the tags to be altered. private void ProcessDicomFiles( RepopulatorUIState options, - Dictionary map) + CsvToDicomTagMapping map) { _logger.Info("Starting directory scan of " + options.DirectoryToProcessInfo.FullName); diff --git a/TemplateBuilder/Repopulator/RepopulatorUI.Designer.cs b/TemplateBuilder/Repopulator/RepopulatorUI.Designer.cs index 4a0edb4..9b36705 100644 --- a/TemplateBuilder/Repopulator/RepopulatorUI.Designer.cs +++ b/TemplateBuilder/Repopulator/RepopulatorUI.Designer.cs @@ -28,6 +28,7 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { + this.components = new System.ComponentModel.Container(); this.btnInputFolder = new System.Windows.Forms.Button(); this.btnOutputFolder = new System.Windows.Forms.Button(); this.cbIncludeSubfolders = new System.Windows.Forms.CheckBox(); @@ -39,20 +40,27 @@ private void InitializeComponent() this.label2 = new System.Windows.Forms.Label(); this.nThreads = new System.Windows.Forms.NumericUpDown(); this.label4 = new System.Windows.Forms.Label(); - this.progressBar1 = new System.Windows.Forms.ProgressBar(); this.lblProgress = new System.Windows.Forms.Label(); this.btnStart = new System.Windows.Forms.Button(); this.tbInputCsv = new System.Windows.Forms.TextBox(); this.label5 = new System.Windows.Forms.Label(); this.btnInputCsv = new System.Windows.Forms.Button(); this.btnValidateCsv = new System.Windows.Forms.Button(); + this.label6 = new System.Windows.Forms.Label(); + this.tbFilenameColumn = new System.Windows.Forms.TextBox(); + this.cbAnonymise = new System.Windows.Forms.CheckBox(); + this.timer1 = new System.Windows.Forms.Timer(this.components); + this.panel1 = new System.Windows.Forms.Panel(); + this.label7 = new System.Windows.Forms.Label(); + this.tbDone = new System.Windows.Forms.TextBox(); ((System.ComponentModel.ISupportInitialize)(this.nThreads)).BeginInit(); + this.panel1.SuspendLayout(); this.SuspendLayout(); // // btnInputFolder // this.btnInputFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnInputFolder.Location = new System.Drawing.Point(496, 28); + this.btnInputFolder.Location = new System.Drawing.Point(671, 28); this.btnInputFolder.Name = "btnInputFolder"; this.btnInputFolder.Size = new System.Drawing.Size(67, 23); this.btnInputFolder.TabIndex = 1; @@ -63,7 +71,7 @@ private void InitializeComponent() // btnOutputFolder // this.btnOutputFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnOutputFolder.Location = new System.Drawing.Point(496, 121); + this.btnOutputFolder.Location = new System.Drawing.Point(671, 131); this.btnOutputFolder.Name = "btnOutputFolder"; this.btnOutputFolder.Size = new System.Drawing.Size(67, 23); this.btnOutputFolder.TabIndex = 10; @@ -101,7 +109,7 @@ private void InitializeComponent() this.tbInputFolder.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.FileSystem; this.tbInputFolder.Location = new System.Drawing.Point(88, 30); this.tbInputFolder.Name = "tbInputFolder"; - this.tbInputFolder.Size = new System.Drawing.Size(402, 20); + this.tbInputFolder.Size = new System.Drawing.Size(577, 20); this.tbInputFolder.TabIndex = 0; this.tbInputFolder.TextChanged += new System.EventHandler(this.tb_TextChanged); // @@ -117,7 +125,7 @@ private void InitializeComponent() // label3 // this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(10, 126); + this.label3.Location = new System.Drawing.Point(10, 136); this.label3.Name = "label3"; this.label3.Size = new System.Drawing.Size(74, 13); this.label3.TabIndex = 4; @@ -129,9 +137,9 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Right))); this.tbOutputFolder.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.Suggest; this.tbOutputFolder.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.FileSystem; - this.tbOutputFolder.Location = new System.Drawing.Point(88, 123); + this.tbOutputFolder.Location = new System.Drawing.Point(88, 133); this.tbOutputFolder.Name = "tbOutputFolder"; - this.tbOutputFolder.Size = new System.Drawing.Size(402, 20); + this.tbOutputFolder.Size = new System.Drawing.Size(577, 20); this.tbOutputFolder.TabIndex = 9; this.tbOutputFolder.TextChanged += new System.EventHandler(this.tb_TextChanged); // @@ -176,19 +184,10 @@ private void InitializeComponent() this.label4.TabIndex = 5; this.label4.Text = "Threads:"; // - // progressBar1 - // - this.progressBar1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.progressBar1.Location = new System.Drawing.Point(8, 178); - this.progressBar1.Name = "progressBar1"; - this.progressBar1.Size = new System.Drawing.Size(556, 10); - this.progressBar1.TabIndex = 8; - // // lblProgress // this.lblProgress.AutoSize = true; - this.lblProgress.Location = new System.Drawing.Point(10, 194); + this.lblProgress.Location = new System.Drawing.Point(2, 189); this.lblProgress.Name = "lblProgress"; this.lblProgress.Size = new System.Drawing.Size(58, 13); this.lblProgress.TabIndex = 9; @@ -196,7 +195,7 @@ private void InitializeComponent() // // btnStart // - this.btnStart.Location = new System.Drawing.Point(218, 149); + this.btnStart.Location = new System.Drawing.Point(218, 159); this.btnStart.Name = "btnStart"; this.btnStart.Size = new System.Drawing.Size(67, 23); this.btnStart.TabIndex = 11; @@ -210,16 +209,16 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Right))); this.tbInputCsv.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.Suggest; this.tbInputCsv.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.FileSystem; - this.tbInputCsv.Location = new System.Drawing.Point(88, 95); + this.tbInputCsv.Location = new System.Drawing.Point(88, 105); this.tbInputCsv.Name = "tbInputCsv"; - this.tbInputCsv.Size = new System.Drawing.Size(402, 20); + this.tbInputCsv.Size = new System.Drawing.Size(577, 20); this.tbInputCsv.TabIndex = 7; this.tbInputCsv.TextChanged += new System.EventHandler(this.tb_TextChanged); // // label5 // this.label5.AutoSize = true; - this.label5.Location = new System.Drawing.Point(10, 98); + this.label5.Location = new System.Drawing.Point(10, 108); this.label5.Name = "label5"; this.label5.Size = new System.Drawing.Size(55, 13); this.label5.TabIndex = 4; @@ -228,7 +227,7 @@ private void InitializeComponent() // btnInputCsv // this.btnInputCsv.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnInputCsv.Location = new System.Drawing.Point(496, 93); + this.btnInputCsv.Location = new System.Drawing.Point(671, 103); this.btnInputCsv.Name = "btnInputCsv"; this.btnInputCsv.Size = new System.Drawing.Size(67, 23); this.btnInputCsv.TabIndex = 8; @@ -238,7 +237,7 @@ private void InitializeComponent() // // btnValidateCsv // - this.btnValidateCsv.Location = new System.Drawing.Point(88, 149); + this.btnValidateCsv.Location = new System.Drawing.Point(88, 159); this.btnValidateCsv.Name = "btnValidateCsv"; this.btnValidateCsv.Size = new System.Drawing.Size(125, 23); this.btnValidateCsv.TabIndex = 11; @@ -246,13 +245,75 @@ private void InitializeComponent() this.btnValidateCsv.UseVisualStyleBackColor = true; this.btnValidateCsv.Click += new System.EventHandler(this.btnValidateCsv_Click); // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(93, 82); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(87, 13); + this.label6.TabIndex = 12; + this.label6.Text = "Filename Column"; + // + // tbFilenameColumn + // + this.tbFilenameColumn.Location = new System.Drawing.Point(186, 79); + this.tbFilenameColumn.Name = "tbFilenameColumn"; + this.tbFilenameColumn.Size = new System.Drawing.Size(205, 20); + this.tbFilenameColumn.TabIndex = 4; + this.tbFilenameColumn.TextChanged += new System.EventHandler(this.tbFilenameColumn_TextChanged); + // + // cbAnonymise + // + this.cbAnonymise.AutoSize = true; + this.cbAnonymise.Location = new System.Drawing.Point(400, 81); + this.cbAnonymise.Name = "cbAnonymise"; + this.cbAnonymise.Size = new System.Drawing.Size(207, 17); + this.cbAnonymise.TabIndex = 13; + this.cbAnonymise.Text = "Anonymise (with FoDicom Anonymizer)"; + this.cbAnonymise.UseVisualStyleBackColor = true; + this.cbAnonymise.CheckedChanged += new System.EventHandler(this.cbAnonymise_CheckedChanged); + // + // timer1 + // + this.timer1.Tick += new System.EventHandler(this.timer1_Tick); + // + // panel1 + // + this.panel1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; + this.panel1.Controls.Add(this.tbDone); + this.panel1.Controls.Add(this.label7); + this.panel1.Dock = System.Windows.Forms.DockStyle.Bottom; + this.panel1.Location = new System.Drawing.Point(0, 207); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(750, 23); + this.panel1.TabIndex = 14; + // + // label7 + // + this.label7.AutoSize = true; + this.label7.Location = new System.Drawing.Point(3, 3); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(36, 13); + this.label7.TabIndex = 9; + this.label7.Text = "Done:"; + // + // tbDone + // + this.tbDone.Location = new System.Drawing.Point(45, 0); + this.tbDone.Name = "tbDone"; + this.tbDone.ReadOnly = true; + this.tbDone.Size = new System.Drawing.Size(166, 20); + this.tbDone.TabIndex = 10; + // // RepopulatorUI // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.panel1); + this.Controls.Add(this.cbAnonymise); + this.Controls.Add(this.label6); this.Controls.Add(this.btnInputCsv); this.Controls.Add(this.lblProgress); - this.Controls.Add(this.progressBar1); this.Controls.Add(this.nThreads); this.Controls.Add(this.label4); this.Controls.Add(this.label2); @@ -262,15 +323,19 @@ private void InitializeComponent() this.Controls.Add(this.tbOutputFolder); this.Controls.Add(this.tbInputCsv); this.Controls.Add(this.tbInputFolder); + this.Controls.Add(this.tbFilenameColumn); this.Controls.Add(this.tbPattern); this.Controls.Add(this.cbIncludeSubfolders); this.Controls.Add(this.btnValidateCsv); this.Controls.Add(this.btnStart); this.Controls.Add(this.btnOutputFolder); this.Controls.Add(this.btnInputFolder); + this.MinimumSize = new System.Drawing.Size(750, 230); this.Name = "RepopulatorUI"; - this.Size = new System.Drawing.Size(575, 214); + this.Size = new System.Drawing.Size(750, 230); ((System.ComponentModel.ISupportInitialize)(this.nThreads)).EndInit(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); @@ -289,12 +354,18 @@ private void InitializeComponent() private System.Windows.Forms.Label label2; private System.Windows.Forms.NumericUpDown nThreads; private System.Windows.Forms.Label label4; - private System.Windows.Forms.ProgressBar progressBar1; private System.Windows.Forms.Label lblProgress; private System.Windows.Forms.Button btnStart; private System.Windows.Forms.TextBox tbInputCsv; private System.Windows.Forms.Label label5; private System.Windows.Forms.Button btnInputCsv; private System.Windows.Forms.Button btnValidateCsv; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.TextBox tbFilenameColumn; + private System.Windows.Forms.CheckBox cbAnonymise; + private System.Windows.Forms.Timer timer1; + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.TextBox tbDone; + private System.Windows.Forms.Label label7; } } diff --git a/TemplateBuilder/Repopulator/RepopulatorUI.cs b/TemplateBuilder/Repopulator/RepopulatorUI.cs index b1b80d6..49309ff 100644 --- a/TemplateBuilder/Repopulator/RepopulatorUI.cs +++ b/TemplateBuilder/Repopulator/RepopulatorUI.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Linq; using System.Windows.Forms; using YamlDotNet.Serialization; @@ -9,6 +10,9 @@ public partial class RepopulatorUI : UserControl { public RepopulatorUIState State; private const string StateFile = "RepopulatorUI.yaml"; + + public DicomRepopulatorProcessor _populator; + public RepopulatorUI() { InitializeComponent(); @@ -28,6 +32,8 @@ public RepopulatorUI() tbOutputFolder.Text = State.OutputFolder; nThreads.Value = Math.Min(Math.Max(nThreads.Minimum,State.NumThreads),nThreads.Maximum); tbPattern.Text = State.Pattern; + tbFilenameColumn.Text = State.FileNameColumn; + cbAnonymise.Checked = State.Anonymise; } } catch (Exception) @@ -42,6 +48,17 @@ private void btnBrowse_Click(object sender, EventArgs e) { var ofd = new OpenFileDialog(); ofd.CheckPathExists = true; + + try + { + if (tbInputCsv.Text != null) + ofd.InitialDirectory = Path.GetDirectoryName(tbInputCsv.Text); + } + catch (Exception) + { + //they typed something odd in there? + } + ofd.Filter = "Comma Separated File|*.csv"; ofd.Multiselect = false; @@ -61,7 +78,16 @@ private void btnBrowse_Click(object sender, EventArgs e) private void btnStart_Click(object sender, EventArgs e) { - + try + { + _populator = new DicomRepopulatorProcessor(); + _populator.Process(State); + } + catch (Exception exception) + { + MessageBox.Show(exception.Message, "Failed", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } private void tb_TextChanged(object sender, EventArgs e) @@ -117,5 +143,30 @@ private void btnValidateCsv_Click(object sender, EventArgs e) MessageBox.Show(log,$"Validation { (built ? "Success" : "Failure" )}",MessageBoxButtons.OK,built ? MessageBoxIcon.Information: MessageBoxIcon.Error); } + + private void tbFilenameColumn_TextChanged(object sender, EventArgs e) + { + State.FileNameColumn = tbFilenameColumn.Text; + SaveState(); + } + + private void cbAnonymise_CheckedChanged(object sender, EventArgs e) + { + State.Anonymise = cbAnonymise.Checked; + SaveState(); + } + + private void timer1_Tick(object sender, EventArgs e) + { + string log = _populator?.MemoryLogTarget?.Logs?.Last(); + + if (log != lblProgress.Text) + lblProgress.Text = log; + + string done = (_populator?.Done ?? 0).ToString("{0:n0}"); + + if(done != tbDone.Text) + tbDone.Text = done; + } } } diff --git a/TemplateBuilder/Repopulator/RepopulatorUI.resx b/TemplateBuilder/Repopulator/RepopulatorUI.resx index 1af7de1..1f666f2 100644 --- a/TemplateBuilder/Repopulator/RepopulatorUI.resx +++ b/TemplateBuilder/Repopulator/RepopulatorUI.resx @@ -117,4 +117,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 17, 17 + \ No newline at end of file diff --git a/TemplateBuilder/Repopulator/RepopulatorUIState.cs b/TemplateBuilder/Repopulator/RepopulatorUIState.cs index 67dd809..7c29a38 100644 --- a/TemplateBuilder/Repopulator/RepopulatorUIState.cs +++ b/TemplateBuilder/Repopulator/RepopulatorUIState.cs @@ -1,5 +1,6 @@ using System.IO; using System.Windows.Input; +using DicomTypeTranslation.TableCreation; using YamlDotNet.Serialization; namespace TemplateBuilder.Repopulator @@ -12,6 +13,8 @@ public class RepopulatorUIState public int NumThreads; public bool IncludeSubdirectories; public string Pattern; + public string FileNameColumn = ImagingTableCreation.RelativeFileArchiveURI; + public bool Anonymise; [YamlIgnore] public DirectoryInfo OutputDirectoryInfo => new DirectoryInfo(OutputFolder); @@ -21,5 +24,7 @@ public class RepopulatorUIState [YamlIgnore] public FileInfo CsvFileInfo => new FileInfo(InputCsv); + + } } \ No newline at end of file From 3935f6baa735390915742ddf88527c216e584d3c Mon Sep 17 00:00:00 2001 From: Thomas Nind Date: Fri, 25 Oct 2019 10:01:59 +0100 Subject: [PATCH 04/19] Added strategy pattern for matching CSV rows to DicomFiles --- .../Repopulator/CsvToDicomColumn.cs | 27 ++++++++++ .../Repopulator/CsvToDicomTagMapping.cs | 34 ++++-------- .../Repopulator/DicomRepopulator.cd | 54 +++++++++++++++++++ .../Repopulator/DicomRepopulator.md | 16 ++++++ .../Repopulator/DicomRepopulatorProcessor.cs | 43 ++++++++++++--- .../Repopulator/IFindFilesForRows.cs | 14 +++++ 6 files changed, 158 insertions(+), 30 deletions(-) create mode 100644 TemplateBuilder/Repopulator/CsvToDicomColumn.cs create mode 100644 TemplateBuilder/Repopulator/DicomRepopulator.cd create mode 100644 TemplateBuilder/Repopulator/DicomRepopulator.md create mode 100644 TemplateBuilder/Repopulator/IFindFilesForRows.cs diff --git a/TemplateBuilder/Repopulator/CsvToDicomColumn.cs b/TemplateBuilder/Repopulator/CsvToDicomColumn.cs new file mode 100644 index 0000000..b1b638c --- /dev/null +++ b/TemplateBuilder/Repopulator/CsvToDicomColumn.cs @@ -0,0 +1,27 @@ +using System; +using Dicom; + +namespace TemplateBuilder.Repopulator +{ + public class CsvToDicomColumn + { + public string Name { get; } + public int Index { get; } + public DicomTag MappedTag { get; } + public bool IsFilePath { get; set; } + + public CsvToDicomColumn(string colName, int index, DicomTag mappedTag, bool isFileColumn) + { + if (mappedTag != null && isFileColumn) + throw new ArgumentException("Column should either be a dicom tag or a file path column not both"); + + if (mappedTag == null && !isFileColumn) + throw new ArgumentException("Column must either contain dicom tags or be a file path column"); + + Name = colName; + Index = index; + MappedTag = mappedTag; + IsFilePath = isFileColumn; + } + } +} \ No newline at end of file diff --git a/TemplateBuilder/Repopulator/CsvToDicomTagMapping.cs b/TemplateBuilder/Repopulator/CsvToDicomTagMapping.cs index d167065..3f5817c 100644 --- a/TemplateBuilder/Repopulator/CsvToDicomTagMapping.cs +++ b/TemplateBuilder/Repopulator/CsvToDicomTagMapping.cs @@ -12,29 +12,9 @@ namespace TemplateBuilder.Repopulator { - class CsvToDicomTagMapping + public class CsvToDicomTagMapping { - public class CsvToDicomColumn - { - public string Name { get; } - public int Index { get; } - public DicomTag MappedTag { get; } - public bool IsFilePath { get; set; } - - public CsvToDicomColumn(string colName, int index, DicomTag mappedTag, bool isFileColumn) - { - if (mappedTag != null && isFileColumn) - throw new ArgumentException("Column should either be a dicom tag or a file path column not both"); - - if (mappedTag == null && !isFileColumn) - throw new ArgumentException("Column must either contain dicom tags or be a file path column"); - - Name = colName; - Index = index; - MappedTag = mappedTag; - IsFilePath = isFileColumn; - } - } + /// /// The column of the CSV which records the file path to the image(s) being processed. These should be expressed @@ -48,12 +28,18 @@ public CsvToDicomColumn(string colName, int index, DicomTag mappedTag, bool isFi /// public List TagColumns = new List(); + /// + /// The file that was read during + /// + public FileInfo CsvFile { get; private set; } + /// /// Clears current column mappings /// public void Clear() { FilenameColumn = null; + CsvFile = null; TagColumns.Clear(); } @@ -71,7 +57,9 @@ public bool BuildMap(RepopulatorUIState state, out string log) StringBuilder sb = new StringBuilder(); try { - using (var reader = new CsvReader(state.CsvFileInfo.OpenText())) + CsvFile = state.CsvFileInfo; + + using (var reader = new CsvReader(CsvFile.OpenText())) { reader.Configuration.TrimOptions = TrimOptions.Trim; reader.Read(); diff --git a/TemplateBuilder/Repopulator/DicomRepopulator.cd b/TemplateBuilder/Repopulator/DicomRepopulator.cd new file mode 100644 index 0000000..d59452f --- /dev/null +++ b/TemplateBuilder/Repopulator/DicomRepopulator.cd @@ -0,0 +1,54 @@ + + + + + + AAAAAQgABAAAAAAAQAECAAQQAAAAAAAEAQAAAAACAAA= + Repopulator\RepopulatorUIState.cs + + + + + + + + + + + + AAAAAAGAAAAAAAAAAAAAAABAAAAAAAAABAAAAARAAAA= + Repopulator\CsvToDicomTagMapping.cs + + + + + + + + + + + + AAAAAAAAAAAAAAAAAAAAAAQAEAAAAAAAAAEAABAAAAA= + Repopulator\CsvToDicomColumn.cs + + + + + + AABAAAAIAAAAASAEAhggAIAAIAAABAAAAAAAAAAAgAA= + Repopulator\DicomRepopulatorProcessor.cs + + + + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAA= + Repopulator\IFindFilesForRows.cs + + + + \ No newline at end of file diff --git a/TemplateBuilder/Repopulator/DicomRepopulator.md b/TemplateBuilder/Repopulator/DicomRepopulator.md new file mode 100644 index 0000000..ea39820 --- /dev/null +++ b/TemplateBuilder/Repopulator/DicomRepopulator.md @@ -0,0 +1,16 @@ +# Dicom Repopulator + +## Background + +The role of this component is to overwrite DicomTags in Dicom images with values provided in a CSV file. + +## Matching Rows to Files + +Each row in the CSV is responsible for updating one or more Dicom images. There are three ways in which dicom files can be located: + + - By file path + - By SopInstanceUID + - By secondary UID (SeriesInstanceUID or StudyInstanceUID) + +### By File Path + diff --git a/TemplateBuilder/Repopulator/DicomRepopulatorProcessor.cs b/TemplateBuilder/Repopulator/DicomRepopulatorProcessor.cs index e53f1f0..d6c2d26 100644 --- a/TemplateBuilder/Repopulator/DicomRepopulatorProcessor.cs +++ b/TemplateBuilder/Repopulator/DicomRepopulatorProcessor.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.IO; using System.Linq; +using System.Reflection; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -27,6 +28,8 @@ public class DicomRepopulatorProcessor private ParallelOptions _parallelOptions; + public IFindFilesForRows FileFindingStrategy { get; } + public MemoryTarget MemoryLogTarget { get; } = new MemoryTarget(); public int Done { get; private set; } @@ -46,10 +49,8 @@ public DicomRepopulatorProcessor(string currentDirectory = null) MemoryLogTarget.Layout = "${level} ${message}"; } - - public int Process(RepopulatorUIState options) { _parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = options.NumThreads }; @@ -64,12 +65,14 @@ public int Process(RepopulatorUIState options) _logger.Info("Starting to process"); _stopwatch = Stopwatch.StartNew(); + //build map from the CSV headers var map = new CsvToDicomTagMapping(); - try { - if(!map.BuildMap(options,out _)) + if(!map.BuildMap(options,out string log)) throw new Exception("Failed to build map"); + + _logger.Info("Map built succesfully:" + log); } catch (ApplicationException e) { @@ -77,9 +80,25 @@ public int Process(RepopulatorUIState options) return -1; } - _logger.Info("Loaded " + map.TagColumns.Count + " rows from " + options.CsvFileInfo.FullName); + var csvFile = options.CsvFileInfo; + _logger.Info("Starting " + csvFile.FullName); + + //now process each row in the CSV and find matching files + using (var reader = new CsvReader(csvFile.OpenText())) + { + reader.Configuration.TrimOptions = TrimOptions.Trim; + while (reader.Read()) + { + var files = FileFindingStrategy.GetPathsFor(reader, map); + + if (files == null || files.Length == 0) + Error("No files found for row", reader.Context.RawRow); + else + foreach (var f in files) + RePopulate(f, map,reader.Context.RawRow); + } + } - try { ProcessDicomFiles(options, map); @@ -103,7 +122,17 @@ public int Process(RepopulatorUIState options) return 0; } - + private void RePopulate(string path, CsvToDicomTagMapping map, int lineNumber) + { + + } + + private void Error(string problemDescription, int lineNumber) + { + _logger.Error($"{problemDescription}:line {lineNumber}"); + } + + /// /// Processes the Dicom files and alters the values according to the replacement dictionary. /// Makes an alternate copy of each Dicom file into the output directory. diff --git a/TemplateBuilder/Repopulator/IFindFilesForRows.cs b/TemplateBuilder/Repopulator/IFindFilesForRows.cs new file mode 100644 index 0000000..8a94f24 --- /dev/null +++ b/TemplateBuilder/Repopulator/IFindFilesForRows.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using CsvHelper; + +namespace TemplateBuilder.Repopulator +{ + public interface IFindFilesForRows + { + string[] GetPathsFor(CsvReader reader, CsvToDicomTagMapping mapping); + } +} From 0197181a3562a3bc0cd4b18164dc544642f13033 Mon Sep 17 00:00:00 2001 From: Thomas Nind Date: Fri, 25 Oct 2019 11:51:17 +0100 Subject: [PATCH 05/19] Added tests project. Added extra mappings file for handling 1 column to multiple tags For example MyDateCol =>StudyDate;SeriesDate; --- TemplateBuilder.sln | 6 ++ .../Repopulator/CsvToDicomColumn.cs | 30 ++++-- .../Repopulator/CsvToDicomTagMapping.cs | 10 +- .../Repopulator/DicomRepopulatorProcessor.cs | 12 ++- .../Repopulator/IFindFilesForRows.cs | 26 ++++- .../Repopulator/RepopulatorUI.Designer.cs | 98 ++++++++++++++++--- TemplateBuilder/Repopulator/RepopulatorUI.cs | 67 ++++++++----- .../Repopulator/RepopulatorUIState.cs | 1 + Tests/CsvToDicomColumnTests.cs | 39 ++++++++ Tests/Properties/AssemblyInfo.cs | 7 ++ Tests/Tests.csproj | 26 +++++ 11 files changed, 267 insertions(+), 55 deletions(-) create mode 100644 Tests/CsvToDicomColumnTests.cs create mode 100644 Tests/Properties/AssemblyInfo.cs create mode 100644 Tests/Tests.csproj diff --git a/TemplateBuilder.sln b/TemplateBuilder.sln index e2d32f4..9fd5703 100644 --- a/TemplateBuilder.sln +++ b/TemplateBuilder.sln @@ -12,6 +12,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionIt README.md = README.md EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{66EED857-25C6-4FF9-967A-333CB151DF0B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -22,6 +24,10 @@ Global {E45F9E94-502F-405E-A92C-18BBA56FF687}.Debug|Any CPU.Build.0 = Debug|Any CPU {E45F9E94-502F-405E-A92C-18BBA56FF687}.Release|Any CPU.ActiveCfg = Release|Any CPU {E45F9E94-502F-405E-A92C-18BBA56FF687}.Release|Any CPU.Build.0 = Release|Any CPU + {66EED857-25C6-4FF9-967A-333CB151DF0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {66EED857-25C6-4FF9-967A-333CB151DF0B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {66EED857-25C6-4FF9-967A-333CB151DF0B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {66EED857-25C6-4FF9-967A-333CB151DF0B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/TemplateBuilder/Repopulator/CsvToDicomColumn.cs b/TemplateBuilder/Repopulator/CsvToDicomColumn.cs index b1b638c..99adede 100644 --- a/TemplateBuilder/Repopulator/CsvToDicomColumn.cs +++ b/TemplateBuilder/Repopulator/CsvToDicomColumn.cs @@ -1,5 +1,9 @@ using System; +using System.Collections.Generic; +using System.Linq; using Dicom; +using DicomTypeTranslation.Elevation; +using DicomTypeTranslation.Elevation.Serialization; namespace TemplateBuilder.Repopulator { @@ -7,20 +11,32 @@ public class CsvToDicomColumn { public string Name { get; } public int Index { get; } - public DicomTag MappedTag { get; } + public HashSet TagsToPopulate { get; } public bool IsFilePath { get; set; } - public CsvToDicomColumn(string colName, int index, DicomTag mappedTag, bool isFileColumn) + + public CsvToDicomColumn(string colName, int index, bool isFileColumn,params DicomTag[] mappedTags) { - if (mappedTag != null && isFileColumn) - throw new ArgumentException("Column should either be a dicom tag or a file path column not both"); + if (mappedTags != null && mappedTags.Any() && isFileColumn) + throw new ArgumentException("Column has ambiguous role, it should either provide dicom tag substitutions or be the file path column not both"); + + if ((mappedTags == null || !mappedTags.Any())&& !isFileColumn) + throw new ArgumentException("Column has no clear role, it should either provide dicom tag substitutions or be the file path column"); + + if (index < 0) + throw new ArgumentException("index cannot be negative"); + + if (mappedTags != null) + { + var sq = mappedTags.FirstOrDefault(t => t.DictionaryEntry.ValueRepresentations.Contains(DicomVR.SQ)); + if(sq != null) + throw new ArgumentException($"Sequence tags are not supported ({sq.DictionaryEntry.Keyword})"); + } - if (mappedTag == null && !isFileColumn) - throw new ArgumentException("Column must either contain dicom tags or be a file path column"); Name = colName; Index = index; - MappedTag = mappedTag; + TagsToPopulate = new HashSet(mappedTags?? new DicomTag[0]); IsFilePath = isFileColumn; } } diff --git a/TemplateBuilder/Repopulator/CsvToDicomTagMapping.cs b/TemplateBuilder/Repopulator/CsvToDicomTagMapping.cs index 3f5817c..09ad4e2 100644 --- a/TemplateBuilder/Repopulator/CsvToDicomTagMapping.cs +++ b/TemplateBuilder/Repopulator/CsvToDicomTagMapping.cs @@ -83,8 +83,8 @@ public bool BuildMap(RepopulatorUIState state, out string log) FilenameColumn = match; else { - if(TagColumns.Any(c=>c.MappedTag == match.MappedTag)) - throw new Exception($"There are 2+ columns that both contain DicomTag '{match.MappedTag}'"); + if(TagColumns.Any(c=>c.TagsToPopulate.Intersect(match.TagsToPopulate).Any())) + throw new Exception($"There are 2+ columns that both populate for one of the DicomTag(s) '{string.Join(",",match.TagsToPopulate)}'"); TagColumns.Add(match); } @@ -117,13 +117,13 @@ public bool BuildMap(RepopulatorUIState state, out string log) public CsvToDicomColumn GetKeyDicomTagAndColumnName(RepopulatorUIState state, string columnName,int index) { if(columnName.Equals(state.FileNameColumn,StringComparison.CurrentCultureIgnoreCase)) - return new CsvToDicomColumn(columnName,index,null,true); + return new CsvToDicomColumn(columnName,index,true); string[] split = columnName.Split(':'); if (split.Length == 1) { var found = DicomDictionary.Default.SingleOrDefault(entry => string.Equals(entry.Keyword ,columnName,StringComparison.CurrentCultureIgnoreCase)); - return found != null ? new CsvToDicomColumn(columnName,index,found.Tag,false) : null; + return found != null ? new CsvToDicomColumn(columnName,index,false,found.Tag) : null; } if(split.Length != 2 || split[0].Length == 0 || split[1].Length == 0) @@ -135,7 +135,7 @@ public CsvToDicomColumn GetKeyDicomTagAndColumnName(RepopulatorUIState state, st var found2 = DicomDictionary.Default.SingleOrDefault(entry => string.Equals(entry.Keyword ,dicomTagString,StringComparison.CurrentCultureIgnoreCase)); - return found2 != null ? new CsvToDicomColumn(columnName, index, found2.Tag, false) : null; + return found2 != null ? new CsvToDicomColumn(columnName, index,false, found2.Tag) : null; } } } diff --git a/TemplateBuilder/Repopulator/DicomRepopulatorProcessor.cs b/TemplateBuilder/Repopulator/DicomRepopulatorProcessor.cs index d6c2d26..e298ba3 100644 --- a/TemplateBuilder/Repopulator/DicomRepopulatorProcessor.cs +++ b/TemplateBuilder/Repopulator/DicomRepopulatorProcessor.cs @@ -28,11 +28,12 @@ public class DicomRepopulatorProcessor private ParallelOptions _parallelOptions; - public IFindFilesForRows FileFindingStrategy { get; } + public IRowsToFiles FileFindingStrategy { get; } public MemoryTarget MemoryLogTarget { get; } = new MemoryTarget(); public int Done { get; private set; } - + public int Errors { get; private set; } + public DicomRepopulatorProcessor(string currentDirectory = null) { string log = Path.Combine(currentDirectory ?? Environment.CurrentDirectory, "NLog.config"); @@ -50,7 +51,6 @@ public DicomRepopulatorProcessor(string currentDirectory = null) MemoryLogTarget.Layout = "${level} ${message}"; } - public int Process(RepopulatorUIState options) { _parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = options.NumThreads }; @@ -92,10 +92,16 @@ public int Process(RepopulatorUIState options) var files = FileFindingStrategy.GetPathsFor(reader, map); if (files == null || files.Length == 0) + { + Errors++; Error("No files found for row", reader.Context.RawRow); + } else foreach (var f in files) + { RePopulate(f, map,reader.Context.RawRow); + Done++; + } } } diff --git a/TemplateBuilder/Repopulator/IFindFilesForRows.cs b/TemplateBuilder/Repopulator/IFindFilesForRows.cs index 8a94f24..d58c62c 100644 --- a/TemplateBuilder/Repopulator/IFindFilesForRows.cs +++ b/TemplateBuilder/Repopulator/IFindFilesForRows.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -7,7 +8,30 @@ namespace TemplateBuilder.Repopulator { - public interface IFindFilesForRows + public interface IRepopulator + { + /// + /// Repopulates the given Dicom with the headers stored in the current + /// using the indexes in the provided. + /// + /// + void Repopulate(FileInfo file, CsvToDicomTagMapping map, string[] row); + } + + + /// + /// Interface for a strategy in which files on disk are enumerated and + /// + public interface IFilesToRows : IRepopulator + { + void Initialize(CsvReader reader, CsvToDicomTagMapping mapping); + } + + /// + /// Interface for a strategy in which the Csv file rows are streamed one at a time and file(s) + /// are returned that match the row. + /// + public interface IRowsToFiles:IRepopulator { string[] GetPathsFor(CsvReader reader, CsvToDicomTagMapping mapping); } diff --git a/TemplateBuilder/Repopulator/RepopulatorUI.Designer.cs b/TemplateBuilder/Repopulator/RepopulatorUI.Designer.cs index 9b36705..f47716a 100644 --- a/TemplateBuilder/Repopulator/RepopulatorUI.Designer.cs +++ b/TemplateBuilder/Repopulator/RepopulatorUI.Designer.cs @@ -51,8 +51,13 @@ private void InitializeComponent() this.cbAnonymise = new System.Windows.Forms.CheckBox(); this.timer1 = new System.Windows.Forms.Timer(this.components); this.panel1 = new System.Windows.Forms.Panel(); - this.label7 = new System.Windows.Forms.Label(); + this.tbErrors = new System.Windows.Forms.TextBox(); + this.label9 = new System.Windows.Forms.Label(); this.tbDone = new System.Windows.Forms.TextBox(); + this.label7 = new System.Windows.Forms.Label(); + this.btnExtraMappings = new System.Windows.Forms.Button(); + this.label8 = new System.Windows.Forms.Label(); + this.tbExtraMappings = new System.Windows.Forms.TextBox(); ((System.ComponentModel.ISupportInitialize)(this.nThreads)).BeginInit(); this.panel1.SuspendLayout(); this.SuspendLayout(); @@ -71,7 +76,7 @@ private void InitializeComponent() // btnOutputFolder // this.btnOutputFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnOutputFolder.Location = new System.Drawing.Point(671, 131); + this.btnOutputFolder.Location = new System.Drawing.Point(671, 158); this.btnOutputFolder.Name = "btnOutputFolder"; this.btnOutputFolder.Size = new System.Drawing.Size(67, 23); this.btnOutputFolder.TabIndex = 10; @@ -125,7 +130,7 @@ private void InitializeComponent() // label3 // this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(10, 136); + this.label3.Location = new System.Drawing.Point(8, 163); this.label3.Name = "label3"; this.label3.Size = new System.Drawing.Size(74, 13); this.label3.TabIndex = 4; @@ -137,7 +142,7 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Right))); this.tbOutputFolder.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.Suggest; this.tbOutputFolder.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.FileSystem; - this.tbOutputFolder.Location = new System.Drawing.Point(88, 133); + this.tbOutputFolder.Location = new System.Drawing.Point(88, 160); this.tbOutputFolder.Name = "tbOutputFolder"; this.tbOutputFolder.Size = new System.Drawing.Size(577, 20); this.tbOutputFolder.TabIndex = 9; @@ -186,8 +191,9 @@ private void InitializeComponent() // // lblProgress // + this.lblProgress.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.lblProgress.AutoSize = true; - this.lblProgress.Location = new System.Drawing.Point(2, 189); + this.lblProgress.Location = new System.Drawing.Point(5, 211); this.lblProgress.Name = "lblProgress"; this.lblProgress.Size = new System.Drawing.Size(58, 13); this.lblProgress.TabIndex = 9; @@ -195,7 +201,7 @@ private void InitializeComponent() // // btnStart // - this.btnStart.Location = new System.Drawing.Point(218, 159); + this.btnStart.Location = new System.Drawing.Point(219, 186); this.btnStart.Name = "btnStart"; this.btnStart.Size = new System.Drawing.Size(67, 23); this.btnStart.TabIndex = 11; @@ -237,7 +243,7 @@ private void InitializeComponent() // // btnValidateCsv // - this.btnValidateCsv.Location = new System.Drawing.Point(88, 159); + this.btnValidateCsv.Location = new System.Drawing.Point(88, 186); this.btnValidateCsv.Name = "btnValidateCsv"; this.btnValidateCsv.Size = new System.Drawing.Size(125, 23); this.btnValidateCsv.TabIndex = 11; @@ -280,14 +286,41 @@ private void InitializeComponent() // panel1 // this.panel1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; + this.panel1.Controls.Add(this.tbErrors); + this.panel1.Controls.Add(this.label9); this.panel1.Controls.Add(this.tbDone); this.panel1.Controls.Add(this.label7); this.panel1.Dock = System.Windows.Forms.DockStyle.Bottom; - this.panel1.Location = new System.Drawing.Point(0, 207); + this.panel1.Location = new System.Drawing.Point(0, 227); this.panel1.Name = "panel1"; this.panel1.Size = new System.Drawing.Size(750, 23); this.panel1.TabIndex = 14; // + // tbErrors + // + this.tbErrors.Location = new System.Drawing.Point(264, 0); + this.tbErrors.Name = "tbErrors"; + this.tbErrors.ReadOnly = true; + this.tbErrors.Size = new System.Drawing.Size(166, 20); + this.tbErrors.TabIndex = 12; + // + // label9 + // + this.label9.AutoSize = true; + this.label9.Location = new System.Drawing.Point(221, 3); + this.label9.Name = "label9"; + this.label9.Size = new System.Drawing.Size(37, 13); + this.label9.TabIndex = 11; + this.label9.Text = "Errors:"; + // + // tbDone + // + this.tbDone.Location = new System.Drawing.Point(45, 0); + this.tbDone.Name = "tbDone"; + this.tbDone.ReadOnly = true; + this.tbDone.Size = new System.Drawing.Size(166, 20); + this.tbDone.TabIndex = 10; + // // label7 // this.label7.AutoSize = true; @@ -297,18 +330,45 @@ private void InitializeComponent() this.label7.TabIndex = 9; this.label7.Text = "Done:"; // - // tbDone + // btnExtraMappings // - this.tbDone.Location = new System.Drawing.Point(45, 0); - this.tbDone.Name = "tbDone"; - this.tbDone.ReadOnly = true; - this.tbDone.Size = new System.Drawing.Size(166, 20); - this.tbDone.TabIndex = 10; + this.btnExtraMappings.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnExtraMappings.Location = new System.Drawing.Point(671, 132); + this.btnExtraMappings.Name = "btnExtraMappings"; + this.btnExtraMappings.Size = new System.Drawing.Size(67, 23); + this.btnExtraMappings.TabIndex = 17; + this.btnExtraMappings.Text = "Browse..."; + this.btnExtraMappings.UseVisualStyleBackColor = true; + this.btnExtraMappings.Click += new System.EventHandler(this.btnBrowse_Click); + // + // label8 + // + this.label8.AutoSize = true; + this.label8.Location = new System.Drawing.Point(4, 137); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(83, 13); + this.label8.TabIndex = 15; + this.label8.Text = "Extra Mappings:"; + // + // tbExtraMappings + // + this.tbExtraMappings.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.tbExtraMappings.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.Suggest; + this.tbExtraMappings.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.FileSystem; + this.tbExtraMappings.Location = new System.Drawing.Point(88, 134); + this.tbExtraMappings.Name = "tbExtraMappings"; + this.tbExtraMappings.Size = new System.Drawing.Size(577, 20); + this.tbExtraMappings.TabIndex = 16; + this.tbExtraMappings.TextChanged += new System.EventHandler(this.tb_TextChanged); // // RepopulatorUI // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.btnExtraMappings); + this.Controls.Add(this.label8); + this.Controls.Add(this.tbExtraMappings); this.Controls.Add(this.panel1); this.Controls.Add(this.cbAnonymise); this.Controls.Add(this.label6); @@ -330,9 +390,10 @@ private void InitializeComponent() this.Controls.Add(this.btnStart); this.Controls.Add(this.btnOutputFolder); this.Controls.Add(this.btnInputFolder); - this.MinimumSize = new System.Drawing.Size(750, 230); + this.MinimumSize = new System.Drawing.Size(750, 250); this.Name = "RepopulatorUI"; - this.Size = new System.Drawing.Size(750, 230); + this.Size = new System.Drawing.Size(750, 250); + this.Load += new System.EventHandler(this.RepopulatorUI_Load); ((System.ComponentModel.ISupportInitialize)(this.nThreads)).EndInit(); this.panel1.ResumeLayout(false); this.panel1.PerformLayout(); @@ -367,5 +428,10 @@ private void InitializeComponent() private System.Windows.Forms.Panel panel1; private System.Windows.Forms.TextBox tbDone; private System.Windows.Forms.Label label7; + private System.Windows.Forms.Button btnExtraMappings; + private System.Windows.Forms.Label label8; + private System.Windows.Forms.TextBox tbExtraMappings; + private System.Windows.Forms.TextBox tbErrors; + private System.Windows.Forms.Label label9; } } diff --git a/TemplateBuilder/Repopulator/RepopulatorUI.cs b/TemplateBuilder/Repopulator/RepopulatorUI.cs index 49309ff..ae04cc3 100644 --- a/TemplateBuilder/Repopulator/RepopulatorUI.cs +++ b/TemplateBuilder/Repopulator/RepopulatorUI.cs @@ -29,6 +29,7 @@ public RepopulatorUI() cbIncludeSubfolders.Checked = State.IncludeSubdirectories; tbInputFolder.Text = State.InputFolder; tbInputCsv.Text = State.InputCsv; + tbExtraMappings.Text = State.InputExtraMappings; tbOutputFolder.Text = State.OutputFolder; nThreads.Value = Math.Min(Math.Max(nThreads.Minimum,State.NumThreads),nThreads.Maximum); tbPattern.Text = State.Pattern; @@ -45,35 +46,43 @@ public RepopulatorUI() private void btnBrowse_Click(object sender, EventArgs e) { if (sender == btnInputCsv) - { - var ofd = new OpenFileDialog(); - ofd.CheckPathExists = true; + BrowseForFile(tbInputCsv, "Comma Separated File|*.csv"); + else if (sender == btnExtraMappings) + BrowseForFile(tbExtraMappings, "Supplemental Mappings File|*.*"); + else if (sender == btnInputFolder) + BrowseForFolder(tbInputFolder); + else if(sender == btnOutputFolder) + BrowseForFolder(tbOutputFolder); + } - try - { - if (tbInputCsv.Text != null) - ofd.InitialDirectory = Path.GetDirectoryName(tbInputCsv.Text); - } - catch (Exception) - { - //they typed something odd in there? - } + private void BrowseForFolder(TextBox destinationTextBox) + { + var ofd = new FolderBrowserDialog(); + if (ofd.ShowDialog() == DialogResult.OK) + destinationTextBox.Text = ofd.SelectedPath; + } - ofd.Filter = "Comma Separated File|*.csv"; - ofd.Multiselect = false; + private void BrowseForFile(TextBox destinationTextBox, string filter) + { + + var ofd = new OpenFileDialog(); + ofd.CheckPathExists = true; - if(ofd.ShowDialog()==DialogResult.OK) - tbInputCsv.Text = ofd.FileName; + try + { + if (destinationTextBox.Text != null) + ofd.InitialDirectory = Path.GetDirectoryName(destinationTextBox.Text); } - else + catch (Exception) { - var ofd = new FolderBrowserDialog(); - if (ofd.ShowDialog() == DialogResult.OK) - { - var tb = sender == btnInputFolder ? tbInputFolder : tbOutputFolder; - tb.Text = ofd.SelectedPath; - } + //they typed something odd in there? } + + ofd.Filter = filter; + ofd.Multiselect = false; + + if(ofd.ShowDialog()==DialogResult.OK) + destinationTextBox.Text = ofd.FileName; } private void btnStart_Click(object sender, EventArgs e) @@ -101,6 +110,8 @@ private void tb_TextChanged(object sender, EventArgs e) if(sender == tbOutputFolder) State.OutputFolder = tbOutputFolder.Text; + if (sender == tbExtraMappings) + State.InputExtraMappings = tbExtraMappings.Text; SaveState(); } @@ -167,6 +178,16 @@ private void timer1_Tick(object sender, EventArgs e) if(done != tbDone.Text) tbDone.Text = done; + + string errors = (_populator?.Errors ?? 0).ToString("{0:n0}"); + + if(done != tbDone.Text) + tbDone.Text = done; + } + + private void RepopulatorUI_Load(object sender, EventArgs e) + { + } } } diff --git a/TemplateBuilder/Repopulator/RepopulatorUIState.cs b/TemplateBuilder/Repopulator/RepopulatorUIState.cs index 7c29a38..41b5de1 100644 --- a/TemplateBuilder/Repopulator/RepopulatorUIState.cs +++ b/TemplateBuilder/Repopulator/RepopulatorUIState.cs @@ -9,6 +9,7 @@ public class RepopulatorUIState { public string InputFolder; public string InputCsv; + public string InputExtraMappings; public string OutputFolder; public int NumThreads; public bool IncludeSubdirectories; diff --git a/Tests/CsvToDicomColumnTests.cs b/Tests/CsvToDicomColumnTests.cs new file mode 100644 index 0000000..9d6c5d8 --- /dev/null +++ b/Tests/CsvToDicomColumnTests.cs @@ -0,0 +1,39 @@ +using System; +using Dicom; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using TemplateBuilder.Repopulator; + +namespace Tests +{ + [TestClass] + public class CsvToDicomColumnTests + { + [TestMethod] + public void NegativeIndex() + { + var ex = Assert.ThrowsException(() => new CsvToDicomColumn("fish", -1, true)); + StringAssert.Contains("index cannot be negative",ex.Message); + } + + [TestMethod] + public void NoClearRole() + { + var ex = Assert.ThrowsException(() => new CsvToDicomColumn("fish", 0, false)); + StringAssert.Contains(ex.Message,"no clear role"); + } + + [TestMethod] + public void TooManyRoles() + { + var ex = Assert.ThrowsException(() => new CsvToDicomColumn("fish", 0, true,DicomTag.ALineRate)); + StringAssert.Contains(ex.Message,"has ambiguous role"); + } + + [TestMethod] + public void SequenceTags() + { + var ex = Assert.ThrowsException(() => new CsvToDicomColumn("fish", 0, false,DicomTag.AbstractPriorCodeSequence)); + StringAssert.Contains(ex.Message,"Sequence tags are not supported (AbstractPriorCodeSequence)"); + } + } +} diff --git a/Tests/Properties/AssemblyInfo.cs b/Tests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..f75068b --- /dev/null +++ b/Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,7 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: ComVisible(false)] + +[assembly: Guid("66eed857-25c6-4ff9-967a-333cb151df0b")] diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj new file mode 100644 index 0000000..72f9d0f --- /dev/null +++ b/Tests/Tests.csproj @@ -0,0 +1,26 @@ + + + {66EED857-25C6-4FF9-967A-333CB151DF0B} + net461 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + Tests + Tests + Copyright © 2019 + + + + + + + + + + + + + + \ No newline at end of file From ed5b00e043675a0d002cac3e1264f966682c54ce Mon Sep 17 00:00:00 2001 From: Thomas Nind Date: Mon, 28 Oct 2019 08:21:09 +0000 Subject: [PATCH 06/19] Split logic into seperate library from UI and added old tests from CLI --- .../CsvToDicomColumn.cs | 4 +- .../CsvToDicomTagMapping.cs | 9 +- .../DicomRepopulator.cd | 0 .../DicomRepopulator.md | 0 .../DicomRepopulatorOptions.cs | 5 +- .../DicomRepopulatorProcessor.cs | 29 +- Repopulator/IFindFilesForRows.cs | 42 +++ Repopulator/Properties/AssemblyInfo.cs | 11 + Repopulator/Repopulator.csproj | 16 + TemplateBuilder.sln | 6 + TemplateBuilder/Form1.cs | 2 +- .../Repopulator/IFindFilesForRows.cs | 38 --- .../RepopulatorUI.Designer.cs | 2 +- .../{Repopulator => }/RepopulatorUI.cs | 11 +- TemplateBuilder/RepopulatorUI.resx | 3 + TemplateBuilder/TemplateBuilder.csproj | 1 + Tests/BasicTest.csv | 2 + Tests/CsvToDicomColumnTests.cs | 21 +- Tests/DicomRepopulatorTests.cs | 289 ++++++++++++++++++ Tests/IM-0001-0013.dcm | Bin 0 -> 241862 bytes Tests/IM-0001-0019.dcm | Bin 0 -> 240874 bytes Tests/KeyNotFirstColumn.csv | 2 + Tests/SpacesInCsvHeaderTest.csv | 2 + Tests/TestDicomFiles.Designer.cs | 83 +++++ .../TestDicomFiles.resx | 10 +- Tests/Tests.csproj | 39 ++- Tests/TwoSeriesCsv.csv | 3 + Tests/WithDate.csv | 2 + 28 files changed, 545 insertions(+), 87 deletions(-) rename {TemplateBuilder/Repopulator => Repopulator}/CsvToDicomColumn.cs (92%) rename {TemplateBuilder/Repopulator => Repopulator}/CsvToDicomTagMapping.cs (94%) rename {TemplateBuilder/Repopulator => Repopulator}/DicomRepopulator.cd (100%) rename {TemplateBuilder/Repopulator => Repopulator}/DicomRepopulator.md (100%) rename TemplateBuilder/Repopulator/RepopulatorUIState.cs => Repopulator/DicomRepopulatorOptions.cs (88%) rename {TemplateBuilder/Repopulator => Repopulator}/DicomRepopulatorProcessor.cs (93%) create mode 100644 Repopulator/IFindFilesForRows.cs create mode 100644 Repopulator/Properties/AssemblyInfo.cs create mode 100644 Repopulator/Repopulator.csproj delete mode 100644 TemplateBuilder/Repopulator/IFindFilesForRows.cs rename TemplateBuilder/{Repopulator => }/RepopulatorUI.Designer.cs (99%) rename TemplateBuilder/{Repopulator => }/RepopulatorUI.cs (94%) create mode 100644 Tests/BasicTest.csv create mode 100644 Tests/DicomRepopulatorTests.cs create mode 100644 Tests/IM-0001-0013.dcm create mode 100644 Tests/IM-0001-0019.dcm create mode 100644 Tests/KeyNotFirstColumn.csv create mode 100644 Tests/SpacesInCsvHeaderTest.csv create mode 100644 Tests/TestDicomFiles.Designer.cs rename TemplateBuilder/Repopulator/RepopulatorUI.resx => Tests/TestDicomFiles.resx (90%) create mode 100644 Tests/TwoSeriesCsv.csv create mode 100644 Tests/WithDate.csv diff --git a/TemplateBuilder/Repopulator/CsvToDicomColumn.cs b/Repopulator/CsvToDicomColumn.cs similarity index 92% rename from TemplateBuilder/Repopulator/CsvToDicomColumn.cs rename to Repopulator/CsvToDicomColumn.cs index 99adede..d7c73ae 100644 --- a/TemplateBuilder/Repopulator/CsvToDicomColumn.cs +++ b/Repopulator/CsvToDicomColumn.cs @@ -2,10 +2,8 @@ using System.Collections.Generic; using System.Linq; using Dicom; -using DicomTypeTranslation.Elevation; -using DicomTypeTranslation.Elevation.Serialization; -namespace TemplateBuilder.Repopulator +namespace Repopulator { public class CsvToDicomColumn { diff --git a/TemplateBuilder/Repopulator/CsvToDicomTagMapping.cs b/Repopulator/CsvToDicomTagMapping.cs similarity index 94% rename from TemplateBuilder/Repopulator/CsvToDicomTagMapping.cs rename to Repopulator/CsvToDicomTagMapping.cs index 09ad4e2..6595046 100644 --- a/TemplateBuilder/Repopulator/CsvToDicomTagMapping.cs +++ b/Repopulator/CsvToDicomTagMapping.cs @@ -3,14 +3,11 @@ using System.IO; using System.Linq; using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; using CsvHelper; using CsvHelper.Configuration; using Dicom; -using DicomTypeTranslation; -namespace TemplateBuilder.Repopulator +namespace Repopulator { public class CsvToDicomTagMapping { @@ -50,7 +47,7 @@ public void Clear() /// /// /// - public bool BuildMap(RepopulatorUIState state, out string log) + public bool BuildMap(DicomRepopulatorOptions state, out string log) { Clear(); @@ -114,7 +111,7 @@ public bool BuildMap(RepopulatorUIState state, out string log) /// /// Get the key DicomTag and associated CSV column name. /// - public CsvToDicomColumn GetKeyDicomTagAndColumnName(RepopulatorUIState state, string columnName,int index) + public CsvToDicomColumn GetKeyDicomTagAndColumnName(DicomRepopulatorOptions state, string columnName,int index) { if(columnName.Equals(state.FileNameColumn,StringComparison.CurrentCultureIgnoreCase)) return new CsvToDicomColumn(columnName,index,true); diff --git a/TemplateBuilder/Repopulator/DicomRepopulator.cd b/Repopulator/DicomRepopulator.cd similarity index 100% rename from TemplateBuilder/Repopulator/DicomRepopulator.cd rename to Repopulator/DicomRepopulator.cd diff --git a/TemplateBuilder/Repopulator/DicomRepopulator.md b/Repopulator/DicomRepopulator.md similarity index 100% rename from TemplateBuilder/Repopulator/DicomRepopulator.md rename to Repopulator/DicomRepopulator.md diff --git a/TemplateBuilder/Repopulator/RepopulatorUIState.cs b/Repopulator/DicomRepopulatorOptions.cs similarity index 88% rename from TemplateBuilder/Repopulator/RepopulatorUIState.cs rename to Repopulator/DicomRepopulatorOptions.cs index 41b5de1..b5e28a5 100644 --- a/TemplateBuilder/Repopulator/RepopulatorUIState.cs +++ b/Repopulator/DicomRepopulatorOptions.cs @@ -1,11 +1,10 @@ using System.IO; -using System.Windows.Input; using DicomTypeTranslation.TableCreation; using YamlDotNet.Serialization; -namespace TemplateBuilder.Repopulator +namespace Repopulator { - public class RepopulatorUIState + public class DicomRepopulatorOptions { public string InputFolder; public string InputCsv; diff --git a/TemplateBuilder/Repopulator/DicomRepopulatorProcessor.cs b/Repopulator/DicomRepopulatorProcessor.cs similarity index 93% rename from TemplateBuilder/Repopulator/DicomRepopulatorProcessor.cs rename to Repopulator/DicomRepopulatorProcessor.cs index e298ba3..431a5bb 100644 --- a/TemplateBuilder/Repopulator/DicomRepopulatorProcessor.cs +++ b/Repopulator/DicomRepopulatorProcessor.cs @@ -3,18 +3,15 @@ using System.Diagnostics; using System.IO; using System.Linq; -using System.Reflection; using System.Text; using System.Threading; using System.Threading.Tasks; -using CsvHelper; -using CsvHelper.Configuration; using Dicom; using DicomTypeTranslation.Helpers; using NLog; using NLog.Targets; -namespace TemplateBuilder.Repopulator +namespace Repopulator { public class DicomRepopulatorProcessor { @@ -28,7 +25,7 @@ public class DicomRepopulatorProcessor private ParallelOptions _parallelOptions; - public IRowsToFiles FileFindingStrategy { get; } + public IRepopulatorMatcher Matcher { get; } public MemoryTarget MemoryLogTarget { get; } = new MemoryTarget(); public int Done { get; private set; } @@ -51,7 +48,7 @@ public DicomRepopulatorProcessor(string currentDirectory = null) MemoryLogTarget.Layout = "${level} ${message}"; } - public int Process(RepopulatorUIState options) + public int Process(DicomRepopulatorOptions options) { _parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = options.NumThreads }; @@ -83,13 +80,22 @@ public int Process(RepopulatorUIState options) var csvFile = options.CsvFileInfo; _logger.Info("Starting " + csvFile.FullName); + RepopulatorJob job; + + //while there are more jobs + while ((job = Matcher.Next()) != null) + { + ProcessJob(job); + } + + /* //now process each row in the CSV and find matching files using (var reader = new CsvReader(csvFile.OpenText())) { reader.Configuration.TrimOptions = TrimOptions.Trim; while (reader.Read()) { - var files = FileFindingStrategy.GetPathsFor(reader, map); + var files = if (files == null || files.Length == 0) { @@ -104,6 +110,7 @@ public int Process(RepopulatorUIState options) } } } + */ try { @@ -128,9 +135,9 @@ public int Process(RepopulatorUIState options) return 0; } - private void RePopulate(string path, CsvToDicomTagMapping map, int lineNumber) + private void ProcessJob(RepopulatorJob job) { - + throw new NotImplementedException(); } private void Error(string problemDescription, int lineNumber) @@ -146,7 +153,7 @@ private void Error(string problemDescription, int lineNumber) /// Options as specified on the command line. /// contains new values for the tags to be altered. private void ProcessDicomFiles( - RepopulatorUIState options, + DicomRepopulatorOptions options, CsvToDicomTagMapping map) { _logger.Info("Starting directory scan of " + options.DirectoryToProcessInfo.FullName); @@ -191,7 +198,7 @@ private void ProcessDicomFile( FileSystemInfo dFilePath, Dictionary keyDicomTagToColumnIndexMapping, Dictionary replacementDict, - RepopulatorUIState options) + DicomRepopulatorOptions options) { _logger.Debug("Processing file " + dFilePath.FullName); diff --git a/Repopulator/IFindFilesForRows.cs b/Repopulator/IFindFilesForRows.cs new file mode 100644 index 0000000..dd8a793 --- /dev/null +++ b/Repopulator/IFindFilesForRows.cs @@ -0,0 +1,42 @@ +using System.IO; + +namespace Repopulator +{ + /// + /// Interface for classes that match Csv rows to files on disk. This could be as simple as following a file URI or as + /// complicated as reading a UID returning the corresponding files + /// + public interface IRepopulatorMatcher + { + /// + /// Returns the next file to be repopulated and the corresponding values to overwrite with. Returns + /// null if there are no more files/rows to process + /// + RepopulatorJob Next(); + } + + public class FilePathMatcher + { + protected DicomRepopulatorOptions Args { get; } + protected CsvToDicomTagMapping Map { get; } + + public FilePathMatcher(CsvToDicomTagMapping map, DicomRepopulatorOptions args) + { + Args = args; + Map = map; + } + } + + public class RepopulatorJob + { + public CsvToDicomTagMapping Map { get; } + public FileInfo File { get; } + public string[] Cells { get; set; } + public RepopulatorJob( CsvToDicomTagMapping map,FileInfo file, string[] cells) + { + File = file; + Map = map; + Cells = cells; + } + } +} diff --git a/Repopulator/Properties/AssemblyInfo.cs b/Repopulator/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..2c06417 --- /dev/null +++ b/Repopulator/Properties/AssemblyInfo.cs @@ -0,0 +1,11 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("3b0e5ac1-5439-470c-832d-7de566b22cd8")] diff --git a/Repopulator/Repopulator.csproj b/Repopulator/Repopulator.csproj new file mode 100644 index 0000000..df49eeb --- /dev/null +++ b/Repopulator/Repopulator.csproj @@ -0,0 +1,16 @@ + + + 3b0e5ac1-5439-470c-832d-7de566b22cd8 + netstandard2.0 + Repopulator + Repopulator + Copyright © 2019 + + + + + + + + + \ No newline at end of file diff --git a/TemplateBuilder.sln b/TemplateBuilder.sln index 9fd5703..1ef6715 100644 --- a/TemplateBuilder.sln +++ b/TemplateBuilder.sln @@ -14,6 +14,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionIt EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{66EED857-25C6-4FF9-967A-333CB151DF0B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Repopulator", "Repopulator\Repopulator.csproj", "{3B0E5AC1-5439-470C-832D-7DE566B22CD8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -28,6 +30,10 @@ Global {66EED857-25C6-4FF9-967A-333CB151DF0B}.Debug|Any CPU.Build.0 = Debug|Any CPU {66EED857-25C6-4FF9-967A-333CB151DF0B}.Release|Any CPU.ActiveCfg = Release|Any CPU {66EED857-25C6-4FF9-967A-333CB151DF0B}.Release|Any CPU.Build.0 = Release|Any CPU + {3B0E5AC1-5439-470C-832D-7DE566B22CD8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3B0E5AC1-5439-470C-832D-7DE566B22CD8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3B0E5AC1-5439-470C-832D-7DE566B22CD8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3B0E5AC1-5439-470C-832D-7DE566B22CD8}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/TemplateBuilder/Form1.cs b/TemplateBuilder/Form1.cs index 2ca0021..7f80997 100644 --- a/TemplateBuilder/Form1.cs +++ b/TemplateBuilder/Form1.cs @@ -443,7 +443,7 @@ private void WindowClicked(object sender, EventArgs e) private void tagPopulatorToolStripMenuItem_Click(object sender, EventArgs e) { - var ui = new Repopulator.RepopulatorUI(); + var ui = new RepopulatorUI(); var dc = new DockContent(); ui.Dock = DockStyle.Fill; diff --git a/TemplateBuilder/Repopulator/IFindFilesForRows.cs b/TemplateBuilder/Repopulator/IFindFilesForRows.cs deleted file mode 100644 index d58c62c..0000000 --- a/TemplateBuilder/Repopulator/IFindFilesForRows.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using CsvHelper; - -namespace TemplateBuilder.Repopulator -{ - public interface IRepopulator - { - /// - /// Repopulates the given Dicom with the headers stored in the current - /// using the indexes in the provided. - /// - /// - void Repopulate(FileInfo file, CsvToDicomTagMapping map, string[] row); - } - - - /// - /// Interface for a strategy in which files on disk are enumerated and - /// - public interface IFilesToRows : IRepopulator - { - void Initialize(CsvReader reader, CsvToDicomTagMapping mapping); - } - - /// - /// Interface for a strategy in which the Csv file rows are streamed one at a time and file(s) - /// are returned that match the row. - /// - public interface IRowsToFiles:IRepopulator - { - string[] GetPathsFor(CsvReader reader, CsvToDicomTagMapping mapping); - } -} diff --git a/TemplateBuilder/Repopulator/RepopulatorUI.Designer.cs b/TemplateBuilder/RepopulatorUI.Designer.cs similarity index 99% rename from TemplateBuilder/Repopulator/RepopulatorUI.Designer.cs rename to TemplateBuilder/RepopulatorUI.Designer.cs index f47716a..ab098b8 100644 --- a/TemplateBuilder/Repopulator/RepopulatorUI.Designer.cs +++ b/TemplateBuilder/RepopulatorUI.Designer.cs @@ -1,4 +1,4 @@ -namespace TemplateBuilder.Repopulator +namespace TemplateBuilder { partial class RepopulatorUI { diff --git a/TemplateBuilder/Repopulator/RepopulatorUI.cs b/TemplateBuilder/RepopulatorUI.cs similarity index 94% rename from TemplateBuilder/Repopulator/RepopulatorUI.cs rename to TemplateBuilder/RepopulatorUI.cs index ae04cc3..0d7bbf6 100644 --- a/TemplateBuilder/Repopulator/RepopulatorUI.cs +++ b/TemplateBuilder/RepopulatorUI.cs @@ -2,13 +2,14 @@ using System.IO; using System.Linq; using System.Windows.Forms; +using Repopulator; using YamlDotNet.Serialization; -namespace TemplateBuilder.Repopulator +namespace TemplateBuilder { public partial class RepopulatorUI : UserControl { - public RepopulatorUIState State; + public DicomRepopulatorOptions State; private const string StateFile = "RepopulatorUI.yaml"; public DicomRepopulatorProcessor _populator; @@ -17,21 +18,21 @@ public RepopulatorUI() { InitializeComponent(); - State = new RepopulatorUIState(); + State = new DicomRepopulatorOptions(); try { if (File.Exists("RepopulatorUI.yaml")) { var des = new Deserializer(); - State = des.Deserialize(File.ReadAllText(StateFile)); + State = des.Deserialize(File.ReadAllText(StateFile)); cbIncludeSubfolders.Checked = State.IncludeSubdirectories; tbInputFolder.Text = State.InputFolder; tbInputCsv.Text = State.InputCsv; tbExtraMappings.Text = State.InputExtraMappings; tbOutputFolder.Text = State.OutputFolder; - nThreads.Value = Math.Min(Math.Max(nThreads.Minimum,State.NumThreads),nThreads.Maximum); + nThreads.Value = Math.Min(Math.Max((decimal) nThreads.Minimum,State.NumThreads),nThreads.Maximum); tbPattern.Text = State.Pattern; tbFilenameColumn.Text = State.FileNameColumn; cbAnonymise.Checked = State.Anonymise; diff --git a/TemplateBuilder/RepopulatorUI.resx b/TemplateBuilder/RepopulatorUI.resx index 1af7de1..1f666f2 100644 --- a/TemplateBuilder/RepopulatorUI.resx +++ b/TemplateBuilder/RepopulatorUI.resx @@ -117,4 +117,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 17, 17 + \ No newline at end of file diff --git a/TemplateBuilder/TemplateBuilder.csproj b/TemplateBuilder/TemplateBuilder.csproj index e272ede..0f1db18 100644 --- a/TemplateBuilder/TemplateBuilder.csproj +++ b/TemplateBuilder/TemplateBuilder.csproj @@ -68,6 +68,7 @@ + True diff --git a/Tests/BasicTest.csv b/Tests/BasicTest.csv new file mode 100644 index 0000000..f521984 --- /dev/null +++ b/Tests/BasicTest.csv @@ -0,0 +1,2 @@ +SeriesInstanceUID,ID +1.2.394,NewPatientID1 diff --git a/Tests/CsvToDicomColumnTests.cs b/Tests/CsvToDicomColumnTests.cs index 9d6c5d8..8a7ee8a 100644 --- a/Tests/CsvToDicomColumnTests.cs +++ b/Tests/CsvToDicomColumnTests.cs @@ -1,38 +1,37 @@ using System; using Dicom; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using TemplateBuilder.Repopulator; +using NUnit.Framework; +using Repopulator; namespace Tests { - [TestClass] public class CsvToDicomColumnTests { - [TestMethod] + [Test] public void NegativeIndex() { - var ex = Assert.ThrowsException(() => new CsvToDicomColumn("fish", -1, true)); + var ex = Assert.Throws(() => new CsvToDicomColumn("fish", -1, true)); StringAssert.Contains("index cannot be negative",ex.Message); } - [TestMethod] + [Test] public void NoClearRole() { - var ex = Assert.ThrowsException(() => new CsvToDicomColumn("fish", 0, false)); + var ex = Assert.Throws(() => new CsvToDicomColumn("fish", 0, false)); StringAssert.Contains(ex.Message,"no clear role"); } - [TestMethod] + [Test] public void TooManyRoles() { - var ex = Assert.ThrowsException(() => new CsvToDicomColumn("fish", 0, true,DicomTag.ALineRate)); + var ex = Assert.Throws(() => new CsvToDicomColumn("fish", 0, true,DicomTag.ALineRate)); StringAssert.Contains(ex.Message,"has ambiguous role"); } - [TestMethod] + [Test] public void SequenceTags() { - var ex = Assert.ThrowsException(() => new CsvToDicomColumn("fish", 0, false,DicomTag.AbstractPriorCodeSequence)); + var ex = Assert.Throws(() => new CsvToDicomColumn("fish", 0, false,DicomTag.AbstractPriorCodeSequence)); StringAssert.Contains(ex.Message,"Sequence tags are not supported (AbstractPriorCodeSequence)"); } } diff --git a/Tests/DicomRepopulatorTests.cs b/Tests/DicomRepopulatorTests.cs new file mode 100644 index 0000000..1c04ccd --- /dev/null +++ b/Tests/DicomRepopulatorTests.cs @@ -0,0 +1,289 @@ +using System.Collections.Generic; +using System.IO; +using Dicom; +using NUnit.Framework; +using Repopulator; + +namespace Tests +{ + [TestFixture] + public class DicomRepopulatorTests + { + private readonly string _inputFileBase = Path.Combine(TestContext.CurrentContext.TestDirectory, "TestInput"); + private readonly string _outputFileBase = Path.Combine(TestContext.CurrentContext.TestDirectory, "TestOutput"); + private readonly string _seriesFilesBase = Path.Combine(TestContext.CurrentContext.TestDirectory, "MultipleSeriesTest"); + + private const string IM_0001_0013_NAME = "IM_0001_0013.dcm"; + private const string IM_0001_0019_NAME = "IM_0001_0019.dcm"; + + [SetUp] + public void SetUp() + { + Directory.CreateDirectory(_inputFileBase); + Directory.CreateDirectory(_outputFileBase); + } + + [TearDown] + public void TearDown() + { + if (Directory.Exists(_inputFileBase)) Directory.Delete(_inputFileBase, true); + if (Directory.Exists(_outputFileBase)) Directory.Delete(_outputFileBase, true); + if (Directory.Exists(_seriesFilesBase)) Directory.Delete(_seriesFilesBase, true); + } + + + [Test] + public void SingleFileBasicOperationTest() + { + string inputDirPath = Path.Combine(_inputFileBase, "SingleFileBasicOperationTest"); + const string testFileName = IM_0001_0013_NAME; + + Directory.CreateDirectory(inputDirPath); + File.WriteAllBytes(Path.Combine(inputDirPath, testFileName), TestDicomFiles.IM_0001_0013); + + string outputDirPath = Path.Combine(_outputFileBase, "SingleFileBasicOperationTest"); + string expectedFile = Path.Combine(outputDirPath, testFileName); + + + var options = new DicomRepopulatorOptions + { + InputCsv = Path.Combine(TestContext.CurrentContext.TestDirectory, "BasicTest.csv"), + InputFolder = inputDirPath, + OutputFolder = outputDirPath, + InputExtraMappings = GenerateExtraMappingsFile("ID:PatientID"), + NumThreads = 4 + }; + + int result = new DicomRepopulatorProcessor(TestContext.CurrentContext.TestDirectory).Process(options); + Assert.AreEqual(0, result); + + Assert.True(File.Exists(expectedFile), "Expected output file {0} to exist", expectedFile); + + DicomFile file = DicomFile.Open(expectedFile); + Assert.AreEqual("NewPatientID1", file.Dataset.GetValue(DicomTag.PatientID, 0)); + } + + [Test] + public void KeyNotFirstColumn() + { + string inputDirPath = Path.Combine(_inputFileBase, "KeyNotFirstColumn"); + const string testFileName = IM_0001_0013_NAME; + + Directory.CreateDirectory(inputDirPath); + File.WriteAllBytes(Path.Combine(inputDirPath, testFileName), TestDicomFiles.IM_0001_0013); + + string outputDirPath = Path.Combine(_outputFileBase, "KeyNotFirstColumn"); + string expectedFile = Path.Combine(outputDirPath, testFileName); + + var options = new DicomRepopulatorOptions + { + InputCsv = Path.Combine(TestContext.CurrentContext.TestDirectory, "KeyNotFirstColumn.csv"), + InputFolder = inputDirPath, + OutputFolder = outputDirPath, + InputExtraMappings = GenerateExtraMappingsFile( "ID:PatientID" ), + NumThreads = 4 + }; + + int result = new DicomRepopulatorProcessor(TestContext.CurrentContext.TestDirectory).Process(options); + Assert.AreEqual(0, result); + + Assert.True(File.Exists(expectedFile), "Expected output file {0} to exist", expectedFile); + + DicomFile file = DicomFile.Open(expectedFile); + Assert.AreEqual("NewPatientID1", file.Dataset.GetValue(DicomTag.PatientID, 0)); + } + + [Test] + public void DateRepopulation() + { + string inputDirPath = Path.Combine(_inputFileBase, "DateRepopulation"); + const string testFileName = IM_0001_0013_NAME; + + Directory.CreateDirectory(inputDirPath); + File.WriteAllBytes(Path.Combine(inputDirPath, testFileName), TestDicomFiles.IM_0001_0013); + + string outputDirPath = Path.Combine(_outputFileBase, "DateRepopulation"); + string expectedFile = Path.Combine(outputDirPath, testFileName); + + var options = new DicomRepopulatorOptions + { + InputCsv = Path.Combine(TestContext.CurrentContext.TestDirectory, "WithDate.csv"), + InputFolder = inputDirPath, + OutputFolder = outputDirPath, + InputExtraMappings = GenerateExtraMappingsFile( "ID:PatientID", "Date:StudyDate" ), + NumThreads = 4 + }; + + int result = new DicomRepopulatorProcessor(TestContext.CurrentContext.TestDirectory).Process(options); + Assert.AreEqual(0, result); + + Assert.True(File.Exists(expectedFile), "Expected output file {0} to exist", expectedFile); + + DicomFile file = DicomFile.Open(expectedFile); + + Assert.AreEqual("NewPatientID1", file.Dataset.GetValue(DicomTag.PatientID, 0)); + Assert.AreEqual("20180601", file.Dataset.GetValue(DicomTag.StudyDate, 0)); + } + + [Test] + public void OneCsvColumnToMultipleDicomTags() + { + string inputDirPath = Path.Combine(_inputFileBase, "OneCsvColumnToMultipleDicomTags"); + const string testFileName = IM_0001_0013_NAME; + + Directory.CreateDirectory(inputDirPath); + File.WriteAllBytes(Path.Combine(inputDirPath, testFileName), TestDicomFiles.IM_0001_0013); + + string outputDirPath = Path.Combine(_outputFileBase, "OneCsvColumnToMultipleDicomTags"); + string expectedFile = Path.Combine(outputDirPath, testFileName); + + var options = new DicomRepopulatorOptions + { + InputCsv = Path.Combine(TestContext.CurrentContext.TestDirectory, "WithDate.csv"), + InputFolder = inputDirPath, + OutputFolder = outputDirPath, + InputExtraMappings = GenerateExtraMappingsFile( "ID:PatientID", "Date:StudyDate", "Date:SeriesDate" ), + NumThreads = 1 + }; + + int result = new DicomRepopulatorProcessor(TestContext.CurrentContext.TestDirectory).Process(options); + Assert.AreEqual(0, result); + + Assert.True(File.Exists(expectedFile), "Expected output file {0} to exist", expectedFile); + + DicomFile file = DicomFile.Open(expectedFile); + Assert.AreEqual("NewPatientID1", file.Dataset.GetValue(DicomTag.PatientID, 0)); + Assert.AreEqual("20180601", file.Dataset.GetValue(DicomTag.StudyDate, 0)); + Assert.AreEqual("20180601", file.Dataset.GetValue(DicomTag.SeriesDate, 0)); + } + + [Test] + public void SpacesInCsvHeaderTest() + { + string inputDirPath = Path.Combine(_inputFileBase, "SpacesInCsvHeaderTest"); + const string testFileName = IM_0001_0013_NAME; + + Directory.CreateDirectory(inputDirPath); + File.WriteAllBytes(Path.Combine(inputDirPath, testFileName), TestDicomFiles.IM_0001_0013); + + string outputDirPath = Path.Combine(_outputFileBase, "SpacesInCsvHeaderTest"); + string expectedFile = Path.Combine(outputDirPath, testFileName); + + var options = new DicomRepopulatorOptions + { + InputCsv = Path.Combine(TestContext.CurrentContext.TestDirectory, "SpacesInCsvHeaderTest.csv"), + InputFolder = inputDirPath, + OutputFolder = outputDirPath, + InputExtraMappings = GenerateExtraMappingsFile( "ID:PatientID" ), + NumThreads = 1 + }; + + int result = new DicomRepopulatorProcessor(TestContext.CurrentContext.TestDirectory).Process(options); + Assert.AreEqual(0, result); + + Assert.True(File.Exists(expectedFile), "Expected output file {0} to exist", expectedFile); + + DicomFile file = DicomFile.Open(expectedFile); + Assert.AreEqual("NewPatientID1", file.Dataset.GetValue(DicomTag.PatientID, 0)); + } + + [Test] + public void MultipleFilesSameSeriesTest() + { + string inputDirPath = Path.Combine(_inputFileBase, "MultipleFilesSameSeriesTest"); + const string testFileName1 = IM_0001_0013_NAME; + const string testFileName2 = IM_0001_0019_NAME; + + Directory.CreateDirectory(inputDirPath); + File.WriteAllBytes(Path.Combine(inputDirPath, testFileName1), TestDicomFiles.IM_0001_0013); + File.WriteAllBytes(Path.Combine(inputDirPath, testFileName2), TestDicomFiles.IM_0001_0013); + + string outputDirPath = Path.Combine(_outputFileBase, "MultipleFilesSameSeriesTest"); + string expectedFile1 = Path.Combine(outputDirPath, testFileName1); + string expectedFile2 = Path.Combine(outputDirPath, testFileName2); + + var options = new DicomRepopulatorOptions + { + InputCsv = Path.Combine(TestContext.CurrentContext.TestDirectory, "BasicTest.csv"), + InputFolder = inputDirPath, + OutputFolder = outputDirPath, + InputExtraMappings = GenerateExtraMappingsFile( "ID:PatientID" ), + NumThreads = 1 + }; + + int result = new DicomRepopulatorProcessor(TestContext.CurrentContext.TestDirectory).Process(options); + Assert.AreEqual(0, result); + + Assert.True(File.Exists(expectedFile1), "Expected output file {0} to exist", expectedFile1); + Assert.True(File.Exists(expectedFile2), "Expected output file {0} to exist", expectedFile2); + + DicomFile file = DicomFile.Open(expectedFile1); + Assert.AreEqual("NewPatientID1", file.Dataset.GetValue(DicomTag.PatientID, 0)); + + file = DicomFile.Open(expectedFile2); + Assert.AreEqual("NewPatientID1", file.Dataset.GetValue(DicomTag.PatientID, 0)); + } + + [Test] + public void MultipleSeriesTest() + { + string inputDirPath = Path.Combine(_seriesFilesBase, "TestInput"); + const string testFileName1 = IM_0001_0013_NAME; + const string testFileName2 = IM_0001_0019_NAME; + + Directory.CreateDirectory(Path.Combine(inputDirPath, "Series1")); + Directory.CreateDirectory(Path.Combine(inputDirPath, "Series2")); + File.WriteAllBytes(Path.Combine(inputDirPath, "Series1", testFileName1), TestDicomFiles.IM_0001_0013); + File.WriteAllBytes(Path.Combine(inputDirPath, "Series1", testFileName2), TestDicomFiles.IM_0001_0013); + File.WriteAllBytes(Path.Combine(inputDirPath, "Series2", testFileName1), TestDicomFiles.IM_0001_0019); + File.WriteAllBytes(Path.Combine(inputDirPath, "Series2", testFileName2), TestDicomFiles.IM_0001_0019); + + string outputDirPath = Path.Combine(_seriesFilesBase, "TestOutput"); + string expectedFile1 = Path.Combine(outputDirPath, "Series1", testFileName1); + string expectedFile2 = Path.Combine(outputDirPath, "Series1", testFileName2); + string expectedFile3 = Path.Combine(outputDirPath, "Series2", testFileName1); + string expectedFile4 = Path.Combine(outputDirPath, "Series2", testFileName2); + + var options = new DicomRepopulatorOptions + { + InputCsv = Path.Combine(TestContext.CurrentContext.TestDirectory, "TwoSeriesCsv.csv"), + InputFolder = inputDirPath, + OutputFolder = outputDirPath, + InputExtraMappings = GenerateExtraMappingsFile( "ID:PatientID" ), + NumThreads = 4 + }; + + int result = new DicomRepopulatorProcessor(TestContext.CurrentContext.TestDirectory).Process(options); + Assert.AreEqual(0, result); + + Assert.True(File.Exists(expectedFile1), "Expected output file {0} to exist", expectedFile1); + Assert.True(File.Exists(expectedFile2), "Expected output file {0} to exist", expectedFile2); + Assert.True(File.Exists(expectedFile3), "Expected output file {0} to exist", expectedFile3); + Assert.True(File.Exists(expectedFile4), "Expected output file {0} to exist", expectedFile4); + + DicomFile file = DicomFile.Open(expectedFile1); + Assert.AreEqual("NewPatientID1", file.Dataset.GetValue(DicomTag.PatientID, 0)); + + file = DicomFile.Open(expectedFile2); + Assert.AreEqual("NewPatientID1", file.Dataset.GetValue(DicomTag.PatientID, 0)); + + file = DicomFile.Open(expectedFile3); + Assert.AreEqual("NewPatientID2", file.Dataset.GetValue(DicomTag.PatientID, 0)); + + file = DicomFile.Open(expectedFile4); + Assert.AreEqual("NewPatientID2", file.Dataset.GetValue(DicomTag.PatientID, 0)); + } + /// + /// Writes the supplied string to "ExtraMappings.csv" in the test directory and returns the path to the file + /// + /// + /// + private string GenerateExtraMappingsFile(params string[] contents) + { + var filePath = Path.Combine(TestContext.CurrentContext.TestDirectory,"ExtraMappings.csv"); + File.WriteAllLines(filePath,contents); + + return filePath; + } + } +} diff --git a/Tests/IM-0001-0013.dcm b/Tests/IM-0001-0013.dcm new file mode 100644 index 0000000000000000000000000000000000000000..6d1f056c5b49b1b93e2ce47e6a90e9c0eaf8860d GIT binary patch literal 241862 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�z1Pe> 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ð&B&=Aj&ztkp=zH;vMpfR$Iz)wSJ>Y#TX@g$nbf~X zM$rX6r>mp-eBQkvuWNs!5_Iy=e~tPo`tc>cThD)=40vfAyxWuMP zx2Bon;&~V562Csp4o#Fu``i*HFa8W^^Y22e?WPvVK{Yfzbpr?0LtZ?$+&^Eh>hUbZ zxc7fwugOj5X+qr}5&H*u@)SA+Vu$eoPDT!kqgA)RQjd|E` zv$o!z+t$I{J~I4uB&L zvG@beDN~G;IfeuECz|EOGzc`}M_d%i{xf%u3{~SM2NAB3>ksXDxTBr?!Alfa&$kB!l#7>1npk@#_d=$$PaYLh12LNG^3e+Cn`FkPA+1q8Um22Zo}5q zoRhrTVTnhqL~M4U<8(k4&65oOK~djOdUS*Pa}ddMT{xJdY&17bYmW1NyjWGC!rw?% zJZWwdc)*(`dw+3w*CVcpz82}+xf6R^Fbsv^6IPV+oaB{1E+@8<6oUKH=1z|S$;_ZL z)*a6D#AW^46TM^Gon~tsRvhrlQ9gsp08sJUkjdN)=kT3jfR|mew)kxE%ql^HcaB*=8~eb^%iif<}mlbD~(6J$FZKu ze9fU>HDx6xgRb6o)kS@%_OfmH+g~^DnuZ-=!}U*SjX}cObB1J$<~M9c`CM#{a-PY) zhpSxY*@^CA@LQljfzfofjG5_{LfQDk^Vrb-UGL)9uN7uHZ~VjgeaiD{ItkRkuk&yH zTlC-!FMLBnH~DopTLEl#xI}=+Wq+Q`o0ugx{ClIuhGo^t*w}P+_W*IPMrn0DNfx}q zvjj_I!rlUbVJ=i!)W*n7exxLTCOx8TL(W;>Rq;s`1)Dc*UyFD!+Pm}G|1^U?iO*sT zOuTEkaKLuKa*GWw4Px_Y9s5f=)|+VNXCS^sg&@Skj&)P2*g}7Y zeS$qPF?2#KE+bbPkJ9IJhk{j}`{RYX(VaW-?-y%lg49`n(N?RAPGvj5DVYqvJcmF( z(%Ir!=(MTj?me${fsHov9~?_I!!mWPTjg4n<-P&z*uzbd#gDPTNy0X=()h;dJ&J_U z8&wSDH=D2wUjwb8eZ3t3+W7WwL~ldh!_QM9raP{d^9_>Zy&qZKS#x`;>O!{fUZ@_r z3I2wdZpRFV%Rh%%D$w7*ROp-Y@$pztiL<~f7=Hs3lhXtB*xTTkf7^h3AVC z&N1C?d(2PN!>U<>wz9MPj1M=%Xku7=0FxPR11%L~D?`r-XO9uakj}+#89Pw3f%eGS zQJW%Hs0?Wmv2|udoOn6%jaUPQ-o2ixf>4Zj_tZ3^=$@PKk;@E6+_y33SKE<*EA?qX z9Zgyc_VDZ2`KbX{ZtGTmUV~kxuf+3>HeXr=<%u)?pgM2|O>y&LZLtmw^pA2fJnx`H z`YDSk10}@~>1G3-XL|vjA8*HcOG^(@m%8Qz*U11qVp@Zh3yWSK!X_^E2hr^Fpubyd zM8%g3FbdH6KdLsEpPu52G>`fe!YRxFSF4ltcB8AXBcl}}aK1^bfYqQ95p8_%5e5HJ z_+rc&kj18jB#hEnJA1-(>P@G{X)8-*;d_pha3d0vAa0=iu1fS1Dr%G{$hj&IY5DUV zwqbH!smd6ma_{9P6J~2{wH5NWA!KOy?{*Uga=7&9z9{?fkI>9kiDgS4hmM zEB*KBs1sXnhI9+w^=FI@iTZZS@y8FeP2A(!PStZp$iCO#Eb*>*HD(80@7#~z#cot2%+cediSY(%nS<0O}dJ(+y# zx=&DtGDQjmPB@XppjCEk0R?+%8e|7mY&2pUGmLO zY9o!L!>~S2Ta1crJc=qyk>$Vcl=&x*#ooBmk?hUFU`Jv7j|$H%w3HKT>SJOSKpq=0 z-79zq-jpehd{XQ`ix$l{0me*l(u(Iuc)R6<)kZLJKl?RZ{w422Ng)y7|X zGF|+1Pq3q84jr=gN2+JcgY+JfR^iXCmos%5Y;z!zgm$n}%n92RiRidd=v&LZgbhX( z%KNsrHIgrKC!1w9<@DQU%6=U;&o<4)QG=eSyo*_BAr0Hb-#I=X`Ae z=;|+WNBGZJ84a$TjJUZZW^ui2>uZ82YNm=sNPSOP`XcwhZp9+k(r>Di{TAb`Nb|(p z%HO8lsM8us&Y^^xTFjO3Pp`yG>9VT$-B3q9ER|T113%vJuH5#&fAfO*dT+C1KRaBt zyLxbVG481GwWvaT>qGhtul!pfX{b4pyy#`$hC_1_X3`{8B~Tl zw@oQNa&(_ZKk*t*oV7X|pOUZHUJvuUkS}&D&!fRjU?!`H+h3dtCfhniy64w8WbGI$ zr0O&82=?gqETgk=+5b)&~pYhVuA6!>IpARnI1V@K#N1P)VnE%e$TrvT_D@axg8 z#0MAK3R2I_-L9fio~>5qTkDEGNEVax07zddXYs*c7M@0p#}q?rDVfC0X@YP2*anjy z%9D}Ua#R4i(4$^^#5c7bX^u3{2yql-`T=W7MI$S-`%E{g;onFMZ#I6jtvGC^*}hu{ zFo1Kr+90g&fwp7;d)bHWv-X_%7`4}%a!h4Tc6eZ6l&K;H2NZJEF)vUMv zGO)@+Jps|L+;)&NNDZ{HU|C`v;;_kt=NtlJ8!T>F*2TXUopj)ldt*~< z>-d&|y&!SG&m!2xuFgUHvWs$}_szR}Vul>Xnp$JDn!3 zpggy`rmY7%Xv${%nK}2y8)!-&pQ?3*6&^C3E}bSU>X-zZ`K~Kmq*7G`o*IfZO7nNe z60|_T5X(Od1{3=!Oh_*1udysgOPVNAdFz5oHJi6%%E%s=b2x?5zn35~8Ml$s|C0aj$d-ST}4*?uTdMYB~*^+bX zeDyO=%m`I**uCS}oJuq3X6Tpm-LAXUudkRNhAp9{j}J6v_P8Dl8u_{CYy8^dY%1Gs zn{bTuC#eOTHB5vGP2dOLkspElt^c5N{{T$p1E8eGA+{hzuB!)4wU#3W#$w-;;4^aj zG_VqPJ0X~|-i+VZ(;Io3Umg}(9$3BxPsZ(>MLQ@qBDC5f^(-$!DR`^5xE(9WA}Pfh ztvF3r9@7~%o~5m|cPncF*I$$R6PE(6et%*#-KLtTG?!+ddW~JqQG2tmx_Ae`x-H0c zKY|}91D`J&5Bib6fb5*{E-KUm!7S|2uKl+y`ZrJhep`hkzL?8HPQThO5ChAFrLLUY zl;;OQfgTQ{67(V-w*4{Z*P{8ZsH%T&8DaVQzg-2PaJ}@U!`(d%IhBg`EPJoFPmEq$ zagJ7P+Sah>p+7NMKYKWuWpAIPYuBZo=g<pxt--|s>a#v`}D}(e2e_5)KuctYxuHCN= zUwE+CazCgQcRlUXg%h2V^mmc<@hdbnwA%2I*4wl9pPgvERNXlYG zc}&fux3WF?_RY1DOQtn$xbqB7%_Loy+Z9+JMX9L9m{-+ZU_mbaroPRf&f&#|4gd3q z-LNlpzM_v@I-ZP$psVagYPU0z(2fp~&x()pEfhr`tM2oQtvNJeg!>aBl`_kVqt_eA{%`PmuFz1^`JFV4p`(CNks(4%+MRZc6ckxsvoFYwW zB-n!VUo0<%6@n51Xb^2WL;BY(#(XO;%^luB3_0fVwcnF&!@vk`{##j`+Lb{lwJrHa z`W_r%Sq|Z(Ak#GJ`lH#Ge)@zum&(vP(~t;kd{=OyDWlc&!gB35OyG)|Y7$Xb>!3^; z(~5Xt8Sf{|rVW}#^?^)ePt8;2@j=~O3LFDQ4C%{V5wpuomNDY&{19NgeckK@)c`2o zW9wpNnyBSc$URiOn{(S8vKb6oMJOYyC3=W#S{_!|p0<5sZPsO1h%XP;S?H>Un zsON~d`#-F5?2B&sWlnSe4>>o$?Rzo}h&t42hdV9Ml>>?{BwBtovl#JNLc81hZa%_w z{@oZW$^C!8V0NMrNLaYEM%sGn#C!JC!N*VFd>%5EEtCJQPsgz?&_UnbBR;RpuOYO@ zc52P)#|ic9kf4{UgjP;#Hy1PfMsi1|HUl_8|Q{ zIRGvzeir6!ydmwEJ9jgOQy#P%j4`uDf>Ie6v_Y&@$w+syqR@-6X7#M<0K7#3BHdjirTh)Tg-hO}TZT#YvZDlDoh+%T{xrZxZ`SyN z`O7KjE}_0p``q*(V!VCwB{6?>!8lLDu+{C}yhCE(jF#pRvzAF~VsdK|_xv7`$?#o4 zf}nI>oRHz`ZFwO(LqB~Kj@ztlGdH{^sJ$cdY8^p-3h>%I&$9}y@g`CWYD5W3n=M21 z*iu;CDrln~1|u45*tlG@WTejFrGvb9Z&!@;1KZDfAEi|Sq+aVPkt6Fi@c&V5XuYCd z?|2BnaK&^lpx*?c%$WsT={|tnUQ$xnX&?^z?aJcbAxUx%68XOUTPxabMh$ag6=$*B zF%7>`e3YA_W4#^4Z>SpGAAJ;?Y?nOl7%b2O6m9H|4tsk29?7O6{3S66;21EdqcxrF zV7MtvTXCHX*(%u|U_x8`vUcc0DfNa@U0|%e!Z!5b<+5n~tvby$dc+}-r+bl`fzSb+ zmj5srG_&A8p2aw+FldBxq9l|?LlB9j*BabH(|p-#;KV_@3!9@}quk}$>OdP^=6OIj zt^=Y4;;MNs?4%gH1Sl+T7M?nFUkN@c7F-w{A9LsYcv2?u+IKMxFMl(!|1XRAoF;je zdt3EE4LRGiY5k1n>R{6=6YwRmi|G)41UQ_g9J39ZImneb zlR#VRcOKCnHNSQKb*|0#%OC1=0e9lEeXCx4MWC|I^pj^X607R(>(=eF;lOO&~Ij(t4`FsXyVCj&>!BIWalV&OzyiN1Q-V3(jZYhQqb_ zq{~U-*Ue&d6M1xtH~1i?168l-ATrJidbypGYpWLEfQ!DQ@tgdT21r#}aKYTp; zS^rSl{9;9UIFulA)%9O}M7XXyR@EiKOeOZJX}28b+QUn=K`z~(gGslFgFMTcT%W5V zO62Hk*-Q-bk{ob6gQ(}(6T&{JL%7kVQLwxddt&f%WFbS?WE@jvDIZ%26eW9Zgqx5} z7vafWpC+vaVOKUis8^43z||+7)xjkjXz(r(1}^a_;GEoT@aL7A9U3UXChibWjlw*= z{aN?@hLsRAk~z{lVleXb=Ws;LW4!<&cdM!KvuP+u!aC%aj# z0h(Zrt69*6Hnz%LIkwNTf9_ThXmN^{TFA6?e_K|@0$b#Hk&mXN;FkSsWwZWbsx(38 z(Lb0Id8H*qh$lki({fPTy^e)52Y~fSS0&$cc84{2o#{Y6r}A6#8r03aWz1jmy~}2? zhx+wL5)dugfr0WYT(HYh1BjB{Px}SMBoIi?BIIzV41=%%kU$wvwp_tEVZr-A!Bvhd z+d89PH}iz|r1pL6627@1aqizFMrO5SY(rkm{5z|p9mpsgc6+isWr(tNV}5Wmj{T!| z`jf(vrrb1MuD(u<&2z`to9;aJ#%VfDjn{NG{-Y{YbZ#Uee5JQFf-M`|4+;WH7e`yC zs#IiWzsUYaWlM23Jd_DJygJSvHeJ`Mrly@({9L|(o>DR4(KN?t1fht&^%oezvc(qaBW_siLaQ@(?dz{S6ZDZ;;8=xoP zE66W|L+l$`!5qh)(^ z^`IQ2^agt%awwS4S@=HBc7{uIUt%?yp+O#Xjta=_&?im9v0DJMwjhzjiU9&q?p8vS z`{`fzt` z#p6bho{CM=bVs*+68-|&iG6NOx*Lpl}+00K@987f1A$BxW=0d znaODij_~qTJH}nRHuXYQfmgjRCx2<)l(&kI(~hOuGB@#U{v}nyKZm@IBdpH{zdW2G zG7hT#BruAGEnX}xGzfsOH)W9ZFL{=AY%By{pnl$ba ziNoZ}-GuSo@hqBgIrg*#d=7)doaSmU%8a~L`ut6+;WvWhV{ubHI8c7gW zL<7US)A@!-=WtFCqG6`TS1LOJLtZrZl^CbO;WgT2pgGCT_>KU zLH+7$ZjY&rWN$mV7vI=HdD=FZA71=$seLuGiCI4Xg5}`Uc;f+Bd58Zn0fM=8CT{`~ z%GL$%v@K9uB{T*?DIL?BkEZkcQCzbeIeK5_IW3@cV{N7#Bb2k4nT|lnHKy5#7k-OL z>xxEDwH&1&cwMy*>GUejs$8i6F=43+?>uR0IZU0fbS^ml7WHj+lcBvj zy z>v!w5DdokcLX0>FUEz-%fWWDwZ~)-IhH*ckI!J>f*(ZgE$9!em+hXKtd&I{ze(mIR zgSB~ogwMbAp>63#!{P8vTjjlvq-)&3=h2@a>-$S`qwJ9{yG5ORTKGaD#kCsP3H3B? zq3-2gxyV>q(Fqp);0~v{*wI$yl5_Jd03gx%# z8s=<3(Wn5nY_sTAU!56BdUB-e~P;uI9&T@u5*xOZ0BiAq zN=t94n8g!c@H&QOULO|CXAFv(RT&6dekZ#c?M3EUK)=|dMTdz_!v8F98@G5mM#-w$ zmb3&%=_`<3vLt90w8nE!YoG1^TOqn0IuYWM<}3-{qwg$4eGhuoWjS(fy5yMeUWR%q zDw%~oOs(<0G}wvOBs0k0XIAXI`y{qG(Ar=MU0K?qoD1#TrblcMUc>!w2tZeMbK8Ff zmmgvCY7fzi%++kdz@{J<7`4~KKA7~XDe$hw~CP6K`bkrw|t1YVkMxAvM1Ip=gatYZJ>YX-%bP9h( z5UO&AX9!`V|`3+>nL+A*lOpz#xZ{nKQNr~j{+bqnIoRv_H)tE|CF~&oHyqR z&MTSqrr++jUPqYZV1I2Tfz50C{#n;S-AdGR5Sdg^nH)RZ=s42Rq}xl&uu4qtiM}0u zK!}Q|WxFr;R?Wj^` z_&eaHbN|hmDy?(y28t0Sdv~K}b$MRvT~Eb?7%7sKV5Wu{Z~RBG5}B9NEDW7P9YyW< zdKvMvarqMGZ;ing&E7xvFtAWH*Uewo6XI!5P`JsB%Ypo%ptTY-;!Ze>Pl zr8uCFqXuyCr*1u)V_8w^b-Cg3Q^!rYjs~}8-RL8+Il0EotIbbc3{Pg-TO`4{$^MNx zJ<|=B+T{)u&|v?mrZdX3%E=Otp`@;?e{Wg;kDp1|E$CI|r-Vz;+ZQWo|1o3vlductfz<)pCW*=dr2IufYgXcFfi0!mZ(oU=3aGqf0%HPDI}korey1^6J*^Q3RD6 z1Z%#JiwZw9#kDw=&HkgX59)D8u)Jw=XVql}^#?6K7|zPAq@8{Ftg(41xO>FHqOT2O z6&chwA0SV3{r_l1GvgZtd=10Xfa{O5kyaClu*sFo3Vs#s$m?c*KQ4lk9V>(6k&Rbg&2wsaXZ91Vx+9wr`lxb#(p(F-y7y!! zVa~V>bFUdsv5t(MZ0R!g+zx+=X^_@+mKosfo5#rc=Am~oSD|mdIx_@Jvg}**>%W;x zoeL;XJ)&{moU$OQ5Lw`ubuQ2Gzd;eLZBekIq0x-49I1T$8gO-Y`Q-d3(L#+PL-cmz z^}*wJvs<>2ADVnpwKg?++V67SJTJwyG~nW!S2@kbmIR6)eUtqJgUKJZ8ACZ+Q|;>A z;wpTY?!E@GrqhQ=W(5HQ!xrh?ohLGZ8@{93*+cs~aT7%+6~mr~NVV7FZl}+qeq@;s z`}mKcvn!fN!N$s?0b++#WZg~oj|%bsCSy_z8tfy*61&7R%8 zJo*mL$I>^M|8)PiY*L2y{4|v4JKd7 z_Hp68p8F%Ke?a|CL5ScDR-{dyOnva<^%&Lfla@7FErYm>q3Na$4;qSB)Bh-}d@o~a zIRBjAJ~v4k7?EUJN;(mi3wKg+Nj$whHoaQ}d>LHUEiv5d6p>mb zQL&9&(=-N@XdtMv)gb4@dv^>1tcAao~?4nUI)^A!GCrGH1WE;W)mP>Dm=x9f6symIL!rU%`u$`PyhkjF~^;6f}K4nl)S{F;rIRM%)1erkvdUnev;p zxHJfTgfv0pZA_cpb)8S!jlp1GC1+#rO54L_)Kk@rBZIKImU4*mw)y(-$T0z8cou$P z?C4OXnhdvl*{Qx_RNV zEG+p&2fWIzzFZP@*Bcq+1X3Z-V=AJL>g%WNss-Cq^F zIg4d#6*Jg`HAy^-BD0kXPY4=lx*X2WG=7q+7G&MYM$eV|f%hy9Yze}rfDJ}XS0F~o z!nv8qFUYT!J<}3ys^H1RM+8qd3BngXG$}H*$tSO319Ix))Rd^q3!FDBkx@7#9uIV+ z&ZmFLTU$PVtUl;e8F!rUPTxO2+`m_E5-E-Gjd}y&03IYHoUhaGKxQ+=NmXNyNDTe* z0bnpkvAOpU!S0tBj0WtBhJ))M%Hp zE^tUxugw&wWREy5qe+$<%SKn(>1G)hfh8MAo^p&67{VG~pYHWw*hm&UlV6fCODOnZ z_JDypVKYGgRLdIln|v{uFl5vPyKI}seHTXM7BCCiN*CR%A9x`Vy3Hx6)|Hi!8yPv-0vC3;f1LY%M9*Xkb3lbH0`4B3gffv(AvO*=b`aesxy7=l%>`bM`E!-}(?5#XFCRwJJYRH8c?*1Oev1G3GhO~J zPZ}2^E$OQvYv@|Z=a_dU&Q8N7RW^!k+1n^B%_ewcZa0~u)FRXPb+wh#25aoc9pQuP zsJO}GLHb(xN<{l6E0W9G%_8;D2C0O7Iu|CaVlA?Qo2dkKSO!II!TUuy?p-VV&(ZT_Zyb}KLJuWj;Wm7>t6lizpZN32VXi)vr4|IKh%T*uHbHp)tSe0wzC+RME zMjoF7jaV3lN~eM$_8BpeK`&eBF7T;C z3N>H)anHxZ2GX@)OV5Uy)?=N`d>7VSEoghDq^py*-FfvOe5CnTQ|9NNM^1xG-_Dky z+dvw57w*$4tuy3bLVv9Vrat9ih8Yk1q~#aYxM?Y#>r9D)0*I?*4fv3;GR_8-OT zai)Nxjh_vY5O?bJFRjXJ5Zd48ckWkQH?WO&RId4}`4I8jG* zf|>{aUDH0X@5B|pd3$@;hmM-^O|*dJ6Sml9=i=MKnk;S?(7jvq7?~gJArF1}F!}kt zo!4)CzoQ$Ba9Y!5swAJTOB{dxE2jTrzfhCMw{>GnDZabXGfFmPqn||%G@Pdp6qLV7 zugHABt!7j~?K8~cqJD=E)VZsXbdAKYF-@}AkueY*%uF>P$qnlf-$=?jl)FRY_fyR) z`QyBS#Luz|!E-dAW@C0}R{-J2NyK%Dtu?zH=i}u;l(`XpeSl1FQW!31HJAbUD84m0 zD07ZGSG=3^wWC#0TaFI2fKnzO&$|6Bm6h-w#*XB-_|uu-$=r~rW+uXhQaUhfdhb)hMK-rG-E{-(j= zjfq*IbEWt)O46jFZiyvSh^@5`c?uq zv%AT0Dt_P(@8ISgxYy@hbA<*j9x8gn{yv{eaY1)I5@kGS$Gq$2QM28jiKHo!uZ7N; zsvioEfeENaf@XR(h@M*hsG9m96TzSq+bEdbIrXxz&r0k#V8_WjaWYo51h+ghH#Q6H zBZn5+i=Juey46uW*W;S@-e=T}^PXDytv(I>_Uo=}c^)Z3TxBZ#euv$lgv-oiSy3+j z6GKlfNalK;avl!ky(J;!Hv!dgNTts<#KH2V;Z-{&uy$Jh}ox8N0p|_*@%(dW*YQ2FG)eRdAQ;4g)SrrLM~mv z(1WaIt?VZN8pdH|G8=tgCGIXCD$uRLE}hKOJ!?nnRlk!Br!xBEnr$w{;P`}Wu6XxB z$LzI!-n>}_w@Z)-aQd^;tF6=qAT>?`v@!2WXwqu{Mbk6Kuyyi+CGnLBn-PB1+;VmM z&Jw)_01!iMs~q@sNcjGf^v8L!FRM@hai6}uTxq`8lj&F*O8f)xfANQ>?dvsG?-6rt zzk0ot>rzYae;5ung;y^nFz&wvblPEqRBvhp`s7QgWwHy1rKnH9ng5WV9x|U)2y+DE ziArl9w1`5^Of|3qAs2;q_bjzhGR9M1J-}u4^;z)S za5l-6mfi;6S+l3#M3&q035eFu4FX|7xEBA)UP7~EfuwO!E~-qz3UL`P8(%RSA|WXB z($9-W&mX6!R)0@u^XE|V#24&mF;!2YaNN}f)wLEXci4{ijI0gY^waYxIS`IX$mmZM zoV#dK%c>z|(<`o0LN%|qpe+T#SrHW2W&`D#56;hewSSCJ0NGT|yPw^-;F9LvmYlhC z9D6-&=#yPI#k^(TKNG*?wHtG!Z3CE+T*m)=KEJ#zn1h14$f10=%%Waa{G(94>e^e6 z5&Fhd&KJ?}%F3zmS^7!`D&4nqT|o$WUHA3DMG>82bqcfmwJ-+)uh}tndP{Tox39aI zPvG;1E$AF87ew#~b}*pQTlb|gREq9migpODgKIu4{w^HbJV`h*UGukwr%oy;`a0Y- zGJ_wN0(gQ}>U*gICq|vr*9OHL>x~Z&u;>M0?_Qmt1O=5-%>%W+TW7m#oY~~the>PC zte>4I{1Af~Hix44oi_O`V@xg&X58)BV~i(eK4abIS!S#lR0kgP1xqwNZikm1Kpco& zR!=iHSi-2xteX9!v$TBE0q;2h#Q31f${ljCcwm2D9be&8h+y#G#$ z#6|zyaj6GCoR}lMnpz@xTEtqOg~DP8^xo|vmYATPDYlk;a#GQ8G(An1f~d3+^95OV zE|X5zi@6mIxhN!VN5$pxg*NRdAy1D_&(Dor8GCgXb(b2TI_xW)r>A1=hYFJDRsdy5 z_%-idfIh?6;dUZUB8h``9DB|DWO$!jXKH&@%c`n4=W$@H8K?ZB=FrIH{~y#;?M~l` z{{AdPrd+RY0r;EY^R-3{uvsll{K7=NO^zY^yx~n=w~TP^Dp4%6KlsMjxOUtK-Yg5P z+U(P@WnU29Rc7!w6V_B}XLhLeqdjSMD}YRM_$C`Wb&j2+f$~WDKlKmw|Rn&d^W!B!}`U8#dC?blI8VgeFEA-=4HR0?Wlb0#ypZTon>`6 zenk6r$0{*~^Ha~&@c$Xdzh`niwGWSZ?lv{*rt&&QB5l;OZ<+HIBjUx8)jCdYw-tV2 zQ1k4{BMjnm_Z4kpF?U-Z7H`DujZ7=A)5c!UV+oBJi~h9QS(vt*b<@2+46f7I*Oz$( z2j5e@Ns^Ppg>!e=JfS?pn)^MGV;OF|W0m`>fO&wiccT>I+;Q30n4)hp zl5vnrs2yRgi94RaGNJ*K>-9$U4x;)H+f~%tZ3&S8*$PZb>1vtDw>iA6%zUEWWb478 zIHG9``^aiM39bO&2)Z$L*>kVC`%OtK^KLa3gHZbVYdUQ;AW9SNti{e|(())rNE=2j zG_0I|_Yly$y)gcdVk2iwxRmFh%5&@~j}GwP<9%p}7Zt%M(}Z-XXMwoV$vXqM1hE=JQwe%{E1^DQD-97*`);@^rvVZfSXD^G;!-a0a)9%k17)QMq^A$ozNU z!M$0I#Y669nO-0B@6OwFCv>}*Wg77*N%Zf!s?J1-EX9JFq_;D`a@){}dOKjg_aNS4 z`zC_zJ3CiyhXz$8CA|BKV5X zzA1WU10&TN9Emr9LhA4rdup_Fhq-^D!Mv?(qBk`ZWTbMbtwlXNZa>+~eb(ab#`@#PgIOSLPxKZp z0~giArK?^$S8O&6359-WAka&`Ui$)+5mcr`<)bTX!={8PyJjv=`ekER!j~>{I77K+oUr<22C@IV%H zi9sPv?BjOUx7j|w=7B5_srz!}L2eKJkc4#>>}Y2K{!xHYw!&VA3$NVzzGdK8;}cO$ zh6!set8EQw^6IOA9ZX66hRTh!7vHl|l1J{H3J!5*#5Fa`cNoY{B9S#v=K3xN`W2lQ zW4E}8gCYh=^7@)qY3W|uM$lG{<5^@&BQ$|)ZzZE)GcFMrA%B1CevW)DfGHNg z!SQkSM*0Zz7V*$~T|r6j*HOdZ*coqgiTkkiEx~%Ti8?`YezFTbfC6k&;d98C*Pdrn zP52msmHFu4q1)V&+=x%DhqOKMIq!dKCEiZu^@sk0ktPdvuX)E&t{MAl3s54_;A$$Hh7e8BB~1>T66P?j}5R#>S9ZwgrT9Y~%-FVu8~G zhH!$*I2r;J-F)3!E3D7=r5SArP6*g+JOqmkwPp?*1A}@5_$}7kZj4G`o_&E2M!9aT z7m^u^B%6FQ-eq6$HHbPLU%e#Z_!N6PXCMNe7Af_Ez5n_Z>U{ zFjzY!F<&~t>W*w$P}GJEl-%;}F z^Y+i4?ssIxnsNIzDkzSV-y#b!;7k5tSbE25_*v7_H%gVG&)Vi&eBDf4Wu4&R<1%IE zEszUSL3v`lDnFA${T$Hhn~5>ssfmv#C328LzRnVVytH2@l5l+T8P|zBol3 zuDK6!8ZIcV&DjA!LdQ^w_%H~)-739PDrtfY_AzUdv{ zv)m2@nIl~0TK-;c$}MD5ByJV+lY0$95+QT4ybdzio-6!cG7durC(6_N*>oxgMTPap zquq&MHtPi$T#>p8k1c9V-Uzq&3g_}Fx7T^TZ)*7Wi(jPMMpbJHJStZ!2b#v&?93 z91;_wUhy5&?z+s{tHl3LQA~R}b+JQyZa%qxpJjG=6%Z)?OY2WJue09lebP|qz31YF zh3qNv`7bf)aF@MTxN90=M4JkZvhx7{qof&c(@vD@4J{c`Wtm%k;6c|cwuI(#VAX^z zU%?)#Z8-&erfeob6%@mADlU1*FFvqKz7zvfCSO#qZqb&P_}oA*<&qjd1nAb0icljy z>D!Y>(WgB>BlM$$y*Aa0wRh&jyt8~FqVh0G_4k|br4k&0FaA;J!1T32l`!gMs_v{0 z$Cfb1^{fk-rPPz6O!;dJrJ}ta+q&)TUNTXu2^|WNtptk&xunA!`+bE+1~P0l4U?5C z@C7wDYs7Du{Nlx@=7bgB9thn!{ZcME{`;Dth3xBzLWw*5H3IuuGdCm{a?5;F6jjlG zkdKTB!00x~WqKGVva}Qj;mOU*1UazF1mV0GQJ#&P{NEec#F4;PmzQFeXuqkkvQZer zLi<$ZDeF(_GB4tle9hzl1!KI2FoCqEhEIN}d+&h;og92?6GRY7c6w}a|kDrxf` zFYnhq#d{r*g?BPnQNIQN3;(lJaVrg@ZZ_l*S)f*g-|f!Mc#@d0HYR52_C8}TR^aZ& zy!QQ38t(Rc@{V+Ni+_JD&CEtED?kwPVo2 zrQWsppOrD2Ty>Y;RRA|sZX;r30{Bn|ykzZ!69B@V333mUfyR1e(rI;;07N85S3wJ| z3Krzq=^cD?zq_)MD4jJ|BsT>V_5)+PATKuWcdurYZVbX6)SVXFX~#pS$iC@okYmc`NQ*$oIUr0(F3YC{jKK$r+tUs_8%l`Z-T5H ze{9vPp3uVQWY@#3`YGv@Em&3pbeOO)$ISR0i3z-X3W zfe=eaU|&D$$v0M~*T$QY&$>i}0*(Dvme*qa!&27+)QTigU+7g@iH9@LFmH(WE4MlG z*;79UVVj6j!*Y-MRcX**CXTIAsP1bW^{~jk$^$0LQqzd!`n$JP^JyQt8aQy zdrL7h4#V8Qxj9d-UnbH?+;UMXzh0p_OtERza7f;=I<4uDN*6kMo*0p}DYM)9_(SNM zgKtDC9`nkGy0RDrj3jBIg6P^*1yy()c=iV+ZA9J2o;Lh#ip|ZY>dj!o1E1KUCCyKq zwVSgv@NFJ-TcNwz{X;C#|Lr^ZyHE5N&9Lr#0*?K6epL)jsnK>aRaZ;po_!kg7m-+r zW(v6(qn8_yt+E;7s$-TX0*dzB%=yY@wSAYsona%a>;P+b#NUeoyb+wb3O~B(OE5;A7ms57r;w7E zO~;za88C7bT@u({_;D*>HW&U)jzoN%q#T$oBUD5SpOXt{tckK>QXRMWL|<+<2MO?Y zM?EWx2NM{+EO9E}l6+U)W+@rB<1fPYOqW)E6Su#vLY&uyFTK5O$PDXg{WiY*W=?9Avi-*iB^UD%FsPcivO}5gTZ|+BFm0ey(`D$VQCZ$o$Ehbz>>H0! zkqHG&$JQq678srNIgyIRZR^j3ydxxU3?x&A&>-L*S~k9Zn9-ul!Au!iU?f6urRSTm z(IdGNv_#L>e27picC>!*srZ#>Yr$KO3`Nz{L^Yp(7iG$Ez5NCI;il#1G}GrJD?c2f ziW>X<`$Zw$bAI%h{)hg~K8sW9Lr+dnz3?o(H8WM`bl#4*RQ_4(#GSe5@&j(Q z0aD;ojuXM|qv>$A(BJ>X2TjLUd%ap}yKNG`mPL@C(nUEQWS#Z>Op361kjLuy@-yQ- z;d^RDF=`ylj|1bmZ3hEEk_7p^ZH8h3n^M*BEbB@uekMjyL?$)=tu-Km>r111N>6Hu zoScPxIl^nMA-;BtBlix7%pHSv9B1r#DJtu_efn#rr+LMSUnj@wndo^VW=9+5Yqa3n zBiZ&RU8@kZ#Wa{acre1El6%-lhuA>pt!IiA9z*Um7XR2V6f2azg0@E1VobUanespQ zH4A!@v{xWf%Y%wnhMSvnf_*CYYXfUeJUz(e$L?MpzC+oem$JSIj*sIiSb6gr;`G@J! z#;K079~Espw40Z-?q+809cObFk-v0#d?>*jg@OvTayk>krXTBfOk@mrHR+=fhF@E5 zMI!$=Ta_Pj+3qi}tOG8i9-_8`(p6s_VGG>grqb0x1>hu3y(_dv|2r+u@<7SD(RIVe(<)% z4+xq8HnuJLZf`D}=Hb9o{@!XsTMCU0!E%Aecnrrn#P0r$PX?sh$yYMledYl)YEaag zpmM{{rrt6l+*oI#O;V`SV#&m~Xz5MS>~X`~GhoG{fKYC^(vVF}p&R{rbAs^(39*XV zpJe5Ky-qJySpQVqJG;H@{N9dr;?v>4W3zRx{ByIO5Mo<9X8j*U5|EbvPAI0+x3m#wK`U%(@wIR=PV(9Tx^kM zq^7w{eMxZ=pnwXx5-yV=pU{U)$#En*Vw>P?W1NWwMXm^G#gFfX^b5?kd0&loX~m(A zVufmE-Zx5`!klKd|4|g4t)EnV<(GK-cT@Y5rN<*BrGz1Wnpqyd=Vs2g^v*wCXSjA< z^ofZIoy_<%CDMj&2{^9);N; z|M=Fp`1Aauc;F-;^4$3E+h4MeUqt>d9c=JKT2S*~Hp&US-!?k_<4vKrJFd(2)j)%2 zUCb510g1+m`+Pu&A53& zW|Ik&Pf^%!o!37=%xow|Vlg4RYg(4^?bH+MiI?fX8uO;5Pm5b})8J_UE}MPo&mpN4 z3kCE{T4eOMH_Wn@FIUMjECTXh<5RJP{-lKRr#1ji!@*VciK9!m2`2LFva5Kyd8^U7 zCC%V;CJrp9Fl2GpViYa;(wjPp2}2gk4WoQ9%ci)MI@zv$k)633oOmWuMYH7=~+C>J?5+EV9g&O=qzD#;tB4BF zbLHVIbs?&=<9-sTHdhH8-@gTON}b({lQgZ~B$~N?_|D3p{H`v9s{8Sc_gVdXow+~x z)+|2JN}jUUFB#nU60yFO(B5!Wkn1aYQ0dLy(+AFPm&^4aX%uj^Smo&3D+O%38vfH` zgiw)aDL=Ii9i2X@!*#bCY?~<$+x}*@`^_Z5FiyX{i_ zH2Lo+51*RRMZ$pBKjIAjDC&!#Pplurj+x3Qktqp;<_WLrMj%M~$K`?(vugf@#nysm8iRg{_f-FxdsZjIJK}ixs{`Ewf;v>bF8J2V zyXS6I)=!TQ%2s8Ic{Fn*=-@qeWGPW@yx-k<TAcW8yez|w^BOlE&h8P3SIC$Z#&JbmR|kiG|U0?C|a|&SY2$O zKe)7zu#lOBQdwQkF#hGUyDX4Ba`d&I^2WJO!;d;cbZ?8Wt>46sb4yV@lh*p?L*=jQ zl^*wY;$(s|+MGRGun&Pq>H23IRjljhx%MIIF?Jk<+?#?s_7i8v6})o{i+oo_nog}k zCp+gp`Cz3Y=NHVQ>!H1{ZL5G`{KY2O#$$Z8y&$yzc6t4>!KFh9OSNVWTNU4Lim~Sb z`DIy4NZsii-=H)iV?w*+^V3Er0pi_&n{l@67>e*m&WV;(PY&OIC1f1XH=m`RbD5Vb zJ@U(B!jR~rUH~|9TVN+|jZmfq{`mC9<76ND=hDxF2IH^3o2If6APBscld>05d}#90 zaylW*+=+PLBtOgC*T^T!Ai3H7-*QM9?9tRqOW^euzC2%O`YoUxZx;Al1^J|6TCqp9 zr$?s-ENL3|3!^EoyisBNSZ%k)>?q64bV*h%U)DVz=997fE=u)?!)7(-X83GD32f+d zook%kUDf@{EDmtUD>BtldFj`U2d1Hv-#@iZl~|UlHiOmc{eh`&3(edmunBA913MQE zO5s{r(PbU{l)T(<6Wma$T1s)AOhV=~67okm4TNE?+?l^k>T&;~adhWPW36gUP zu^oS(@V%IrVNyEkGuJT&tjlZ*^vW(>xljgq9)epkPl7cK%eBm|8y=xwk0Z!dZ-hD} zo`Z`{07y*^J2YCYFsA2Si*PBb29JO{y_$eitq+f7USzGvUDF$q6SE4(Y{{A}PRb5^ zRBb8L=lgYOZ=q`9e-S~*aeyBngDk!2hep+wHYCcn-qQ$3jZ<*7Win7UrT28IUZE1< zwQuZYv8GvE!kI|~Hc*z%z|}CmU+1Jt*JoDKr2;~vQw@w>B*ou;+#Qvb@JL6fX7}X- z&m8!ZK5L!Nx2&SR&7ZKbACSyxrM}0p-Q4T@pQfU*pO!A$V?Ih0NOCcT_t|*WB{Eap zf2DCd1>h-Syry!=3J02fC{S0|PLI>QGF?id@`2ZAf0188%S6=y_Ut~TE3`{GRxSql z#DVK)N!F7Q!x>WA0XDAmm&wozgx-Kd`C;b1Qx4tNaTvDMI9jLLRiJR=&dvGee-vd^ z`0N-0YX6)Ia(J_+kU4i9bz3#S5v;XleAA6|sy-apyanP>jp9ACL+O1;_X^U$d3)UE zD0Iok0pw4sc6;x9By8=s^BHN^RZ9JipjmHU3)`ryKUw(NmUxaOoGtGweH1s9*kz$R z;Kj7~aQ=xv2bBhWk}m_bXJ>WPHs^H>2OgwsO&iTo<-1PGRzg{`yi~SiHNnVy(2ZG( zN^FRKy+J+p3G!3ZYs;MjT$UR`7MF7VwC_x}dp1#XPL5YN>+i9)f!bo0W%RvjjSz~t z_d3nD!GzR|$b1xmgi5l!v^LO@`gR%pbByd7YpE8ru_GmnalS8d-Ez?9T6#9vuV786DYF@43`!)H>UEgC43I~7i zUB(z{j^>MI3UR7d-vqF`C>P2-BK>Y4nDvD3|IggvUN0}=7N)i*qv7^Lae$Ef$B)DQ zWv`>=RNjl6PbUqSUvU8=%%LMHpXzBUvPmTdOT6X!^}zDo3k+27;I#&s?uf<@G;O-vM-H&F64#X;oWb}-!p^zV zB(j$_bxJpMdN!QDXs8G1vlAGBDAU)5J=0q^O(^^82q+9VF6afF&3K~Zl&c`DJ}wc7 zm{I0KpC@A(j8`{3TkHBiRl@r}K{nn3ah9Nuh&$&&JX*=g%p$gt4=<3YZJiK>3h|T@{P@gTQBLO5PJ)7qW|5Jn zR}N}&ycyKyfir-m^uMH0-?I_XuaYwyX=zCQ*-Gm!n<-=IU=c0m{j;J4f=I&RhIh6n2>U4){$hG^?xzqNy97kZ`U&_!j5_!ekd*h!J|rm>zbsq zkb$?+^dh{@i~GCb+9wS^n06ph&+Xjmo^cCQ1MAEYv3koffe7|(!PCc9ju-_Wi<8xl zH=q$M8HWm*5NfG94atF4Oa9tspvs#3domPn>opZFu^?~3I?5`87{Xr}t_QK>3LAWF zNl%r0a`eE=WhQKcd3tdU#jZtt*DA~Yse$J)I|-8$2?VpiZrrt|IY0vaVJc&(MPn zO?x=&Zq0?Lu3DLT&*Ohu$Bsq-dRX}_H&Fv>+FnITxz6%(I0*-}Ntwy=3ZI~sHcMjt zuhA?!+O7V2_spm6V3!Q+b+kMOdi)yq`R-7aY5QYPavt5c}7b^h}M;s zJB$eu)Urc8Q9|7gAHOjRvzfw=Fsg1hOhvpT zx_KqYO>>)Av&lXAw`#OzCie#noF^TEfF)rJ-Aze4iDJw zEi3Dk8h5E)HDa{gY~GQg-LWZUzGTMJ%P{e)#m>1f&G+>7kEh+z#3}C6`yJN7q;p;K zqwlhr#o5*Vx=SaR`O{c2dvr}cYi?58y>E88T*);Eus9DbuH)@+`$BQ^{!LxpGtZg> zZU3d)Jjuz#Tbakqi&7RwB2)5*pQWgxAAv2^GZRu z%ct)CYgH3ZXv$e<(w(gWntTCeziY75lT|JOEP7y(gt>~0y5z%U6Y-Nr;R@BT>*vB% zuR4?4LI zd^1#2B{tVGCLfK@IoWl38#>%I>nFX=jO-5zQU=nXv89;}|E66|D^(U;Cv z;$k)&$q|}xdsnLBsK^u+#Po1n(%XrVE$I{HhQx!CpGLFxy8ndC(%59t{EOH`T}II_(kGM{q^LYADq>^)F!5@(<);xs_$`%(W&btj}>P`OM;F~ z#}L?Dbol9IUJk(J3&NK{k>=gxS1Ulxw%)4j>gZ*#g=&F&_NO>y{FR6A-N$aqMLh9t zTdRDts(2qcpQCuu>|6AY0y6`PoN4;8njILr#bqMadaMn~mUy())dXnkzT>eM#kT|3J+)K4|-Mv`0T4cC_>np?WKf`f8+o{A;G?(>+M0O#U8+XMal>L0g z*s+-q`dkl^sqx*sB(Zf6pYefuWDQ%-ukCsQlqb`fxtt@)q*+!?srD*kt?Z|fkE+*F zu!te{m|XE5H~jLP|x(}<%teGY+7q$;~A|-jx=J5=h~(`imZO<8!!Te z)fG=}JbWj^gi39P>Cu~O#8G48lFt#UjXvY?lFLKcr=>?!`hog?drj9+s3LJB0R_X_ z7#Ugh+-yPrHdX`T*s3iCOFVbqGtg=ZB#LY{oH>)p2a`z88dvgU0gZ*%4nyF@@|L-A z_o1C5kSVt5pf>d0JO67%PBNDIuc!Ufv^qldk~SXpk<>?2yL*fPni5>sy=QzH_h|py zUkGM@TT**W6BTyR!iInG_|)y0$eB;pUKe${DCj+R57H6vYjJ>K;0xk|MeL0QFcpy1 zuU@8WHFu%{fEYdW#R|dW%bNg9CM`9>7N8U;Ho+-FR(Z4woO#z^cQBw{KFUVI7wgn; zB>$cwsN=aOJie$@Mk`M3OIz^45;Hd;sqLZ%A+>Ry;5kE}nse%BUHkH}p{9Hm6aUTU zeiMNTWKkyb?GjX&onM8SltRZcsTbpdBr?XoTa}Y$>T!qhnGfJ-z54fqRX&&Dph71% z9KOmoS3x++VH@pr!B#SuSDtD=mbtPo zg3h2P;J#{%lm0pFw)M`!16LvKUzH-GNykB?m7MI>=1a~Q)~lR8LN@ZGTW`K-q=yN; zOc{7ajT>E1y!Z_8v04fMTCFE<~b0?k+f*)6smC{uZ5hi-=X-=^GD! z*}zkY4L~84ppH?Es#C*$gOBOx{2W1TM^cxX8Cm*wSjFGHrl$y0b{11zX*9tc^qVMc zvFdn~3%04k!mgg4knzu5)G>auIS0W=-dQkACx(n9F*Y8j{8@ngm>n+qt>4vwL`)si zUG2%&xlCULS@@qLy~At<+MqLFTYHBc*~c>zkQU~_M#;Hj;C@4lSiL=w@AUq5@{$GQ z8)`4|%Pit9T__skc0NE(z=il6_X($D^)&>Tx_c+cdh7I&9gYdj$dj<#Ei4`6%1W1X ziT}r3C}#X{yCvTGyIWl%mjxvf=R9}K_1w^KFXLBC{K*{0 z^+(Q^R{DHULuEQy;mEz3%sbPV8tGpv*b_3)nvj3=)#51AuYW>(SeT9V8bi+WGrx4< z%YP+^loNQkwSm^a!&l9TpNdJ>#$(^+MTqMCaW&R(K+iy(NxRQVeRk(MTrbmkeH|LN z2M=0+*9I)Ea>RZ7TWdl?c@;M3uJEkkVbt|eq7vG*4_Q}B?IH+7%f_Hyj%Fq1A2npH z%4>{_-|p#q!$N&MjZq`@{f{AyqtXZ0oN;l09~B=YlLnNNc*X_UgKqV-?j6s5Py6c- zcK_tjf6;=c_RLZIK??7ewb&)$5$!3qsyC@iqFFzm`~TQ}BS>@ohL73+(D+8GeRWEv zcq5tOrS>OgW^--^y1Q>%4s8&}!n)w3i4Ib0HG44pgE{D~M2tnh@YTNI7X2|mK(Z7PxfC^Yd|;BE_=H?DDV!!lGFu`L#lK2TPZ(y-E+5l?YX zrwDSKq{#{SU z8VaehI>d)h33#1t+m|blHjoVXl^c;IJ22 z;a;7hRV=SrYf>wE@Ob3S!?-P-pJeqJpqB*nv{!NJ@E^qsXDdGn#f{w`-*q;ur6x#i z3!7o@%U7A+LBG{XHpHz#-c`*?*bE1$mCS6SE!sinAhO()T;aTI5LQ*JcF6R(I991L zBC)gBiU-~dgmL1guBybxkIbO`->Qy>9S5sT9d1_>5H4s5QZ|Qk_N^detXz?qS7y0u zVxd0TLqch#(k^Jp7L${p^#ZnOCyu`odb>2CV9DVaI8CB^+eGDLW<4 zb&_9zNj|$~O~B}akb>I$?)7FGPMi{o-_(%ncWLoKsL=!jYwGJyww> z4d0cY*-0p!JDteXjuR_;zC4d|w$fyt4>Yy}Qj}6`N*;XMuzzXCRa?(Up-6X^gmibe)Ha&Ypdww;-Q7L9Te`Nv z=x!uNqc87opYPxBoEy)*=blrOT^E0zN$$Ye8&>B;m)Js$uF&e?^!4~qPXth&9loWO z?N?T|e*r{CR6=*|c>{}&WzLD-2VhWsKV>!F)hzCDFyFVmM0=$w-kPBN+oO0{nJXiz zAHcet{NL|Ke1}{M)jQ+3kD4`7V=PQ@(@P}Vqt?cusG#6wKp&$mlPoz63xS1mzH(fg zixrzJ4TB7yx)uQ|zt;06z4YiXWa$*YU?r};lswLqxFc}yp?&zdPiBG8e$$!97Q7lPMqT6mP&9^^YReZN;AvKHVVt`FT~Twtyqt8fql zSg@(V_{Fad^hH}omO@qh4mSNwmU9dOet9G#zuD{&W>o)KGfGw)XXosGl0CpoFW;MP zn#$;w03x6ZMZ5+k|4S$OZpITAM$F!nf)YAYY+s-T+q0f_8Wep^&W0;4pJM9o+joOKn`6FEi8 zq6d4!8jOBO{!h(tuU#6FPze@{5x*6d+(VU%joSa46u?=cM$C#;4oiKo38=swr|J1F z|DuXeiZY!moH`1dGJ*8+77)IaWAhu zsS?maS;>lUEi!hd5`>%~2prI49k@JQMX@hNP&%6|^G;(MBfjSRMKXyPh2z>Gs^KL>}NA< z;LI)u!WcRF$A4>VQ|?IA-AYFAqsbEvN>*|Th?uKS?rjkniNS7$Zp9tz**ujV__J)` zlax))M<$U&!s%;WQ3oJ&;|>!_*N5)rlTeLI@uK>ZEh6&OeuRZkpd7F|p~;>K%Qhbj zBGHg&;h0}hia{P!6<8J@WwA|)Rt)6`1kgPP@=(NV(+;dTVC1RpOs|xjMFTw(L;uo= z#CcCVqTQGqj=&p#3i7_n?kj^rY)y}2{I*tnA#IXRCN)JlXytZLsw`Vd^l($&#}Q=2 zT(i<5b9FN;X-b)r>BG>bBn=iTC9d)D^ualy~tEGM{|!~JrNf+zoa zuIp)PmdOrBI;CW}Wlymw=m!g3t}Xo#cMhM`=5Jn7=|X)>Oj67D#+{M$@L63qQeft? z)c_f3VR42AZO2wxG>OpvK%;5Q;u~~WDf^JudPK+VP8Dc)0TSz6N9cLb4|OKHzJ(Nt;}kFWoEuVK2M(~b1v zA&X8TY;I~I8}O`1tD5j42gBl_H35`ge~J$tK^?sp`H?@f=FC>Q^~LAGol_u>!T1VQ zdWWQP*G!B6p3DkB5T`jP(Y#Bs0(5`TT)IBpYgfJ@@=l8c-?W-R+>FQrdgsmLh#moBfPZ z?+4vJ2|!((9jC_m`=MX@8-15ns6-naD0+YBjw!JwYNk;^Y-188==-txPilHw)yh>< z(`#Y@es-D1Nx~AzV+_K#acrGbdC*Rb|blAS0d!!);CL1|Y z6B;@wI#};o$o~AF@}ajph4Ee7XcUr0L#XgplivFzK(du*nVQs|uucZ^{q9@L?S29a z>014l3%0*Jir$HjoyChY7wY<2f9<;%q=bFG+57tJVUM^mpLMtSmPVc+=RC&eH+`Z> zpX;-V`~pK_nV9dadcFQ&0g&|7Cz&+M;SM8&KT%wb9mh_KjRfXGO!=H$`n6ulcbXWM zycG7bYq(}k&SOKYN%7+|{>e@dv8{4g`rEg11M;4_@(*nTMUgBv!-))!8qVJ^jfq`A zCrs07_@a$h^n$uLFPhc-LyqoE%lBieXiP+YeC)WBK8Nj+NPs5lnjuuHCk;2mD^0J< z@iOIYAoE0Y2<9m@7&Rzs!KM;gf>5i|E7m&t^;=(_hoJNiPs@qQHvzp_OdtiWk{%2s z@+R6%({9ptnVvzqr8(b7DB>6;&Y&;uipsm zy{_~~qe|3CSeBV_&myAqFJyK>gl##Blq;`RW|e5^J5?m0^ngv4eb721GmW}i=yt~X zjbtC^wU-D7Jb>UAUUe1sK6!;Xa!UJ%-K^>wf5taO;Ez9=6-+R2XN?uNexa$CKXg(6 zMFxo~a>3baLBaD=|L0?IUSIT4b#bRBY$Xaxu$-_y8usHm`hnM%VF3nTLahI`l8PsI zFf1mQ>B=!y7LKp4MqEB^rt#`_iT;t4D~uZ5uWg9mr1Rrb*%FMZ<)t%D&2#e`>njvP z8!h_KNdz65{9xBnR z2WH`3m}T>uLOQ`_(-P%0TEd$T)Qhzzl}A*vs457HMVD}P4>JXacD>I)pHA|LPDpN* zUJXl+{S|~i@bihfp_blGEm&uuA&sc%O`iRd+t~{;Abih~b3!%rC%em?Q7@oMc(gX_ z%eC5(fWKpO;N{VJ&Cn`Gzde$Fb2Vem;aDZ3{*+zklgCWs30Lm^1BTD>N122c`NEmv zljs`$xX;)}s3;9qjqMuHBpxFxhqq1@P}|>B*XHX_L2m$EqE|%)_GWIvm^3P#Tua6d?ODZxp9s&+il}B< zdL&y4{E zNDkkzuKsR7ExQ9XW6k;y7I`e`+RxVld`DwCTOqk5<^v}_sLN?K zQ^Tv4PppZ%+Is&YQJrO%2OUWDRbf`GWke&6DV3w4q{btoZi+lS0(le9(y)U-`fYH?=MJ%dcP0{6lihl$8 zn+vHRvhl@6YvH%I+{XG1gF~NP-jZQykMX8j^o~$`>_gNvC3bw1%A(pL_@gsytd181tVI^N9 zz%b-_4^tKfV{Q<@|FkW+n64gdU<3vura5KoWAksk(n8l~Cs^>7va%Aox& zB{PrQaXg#p#C0eI^g`(Am*OrAQM_h!~gud-=x8D;JaT#Xmlf< zj>w#8iOQTWZI45cO;d?E^K}Qs&rD$4jAj9G=#7e7lk3-72&YAt!Tl2{QJ6cMl1Af6 z=l2~uR+r7p#zmt7D3)o2w*AW+)pN0G-t4w8O<&6w_}4C)3ERHAT+*l^^10<8TMPI1 zRR(g;?5@ubgarecPhN|L0=qP0)jm8s%G%0|sjT97T(&I;A;r)*n}I>kSG()n#w~H% zU&)kzvuiEee<90Utf~8{aRhS?j|z9$RPg?v$8T1f&6OWg$m~ax5HGIN)xs+9UNPBwQT#88M1DC4c=Sze>eX` zR?m?U>9=&(u*b;7Rae&L=QzDY;E~07Bk5T6^Ps?^&0qXAxj$3sCcNP!y_?JrG5fXs z@}y?ov3rpiH?r2O4DeE#{I(x*z!xzp7U@SzE&c_698*8sye{`0mWt2Z%+nWd7`bMt zLPVJK1N9YB#83+zFLXO?kljf5{uV_i9ZW?tBjq)`t44E)!Rw+XU?jj8@;CIU{eB}q z!1Z}%)wX-dpO44_wXvi#N;)hw-3+ZZiJvR*snAa?-Tob5)2f(kO1m&=TVBC1&>c5o znDO|ay3^*=B*s(i)`GC@QlB5$vefjT{xQA0Gft^;(Y^f6IBPccJ((O}S zMPpfB&xMbMzx}v4Jcv*D7eD=fy1tGj**$J$yEqFD(Hm|&-SIbJ;>!ESBk}w4d#l4F zL!8>*);=i3nSrfbhJW*}yR;Ju2 zvTIuw)2PZdyVgoH9L0?TH(aSnChwZO_q7>;i9&_)P;7xzeQVs0zvph&%Ko9`N))F= zvrCsitW|`};;0Ku8;`f%2`^SeZtktHT4Sd=w!LMQm2eV}U)Z_%3oo<(rCU!cwn!mg zrJGCXp&D!~%SN0*K&E+KXeVwFhv+0w+AvF9QpXTJ--SqcIhZcpYaz3HO~mG@6wF~w zEc_!Z$_wQ6L9f;t!9tHypsGnDjZ4|oxcbTkki8DQ7aSJO3;I%H2?u?ES86|X9J^|Z znW7GYMUQ~}lw;fQDz_5aLzMK(#4f|fx?QFeW=!_q517{v`;eZB!x+G3l>&N|M%hm= z4K!w&V%QkB7}F3Ks#tE~Q()Z=<*gA@FLuOB-FGwON#-L1AjtO&5#Zj4k8M_#lu;5w z&PVS`2`91`6D9x9awV1t2?rpAo3yW5PCR7cE3bz|0gi1C_$y1pyEItA?fYx#kLVQ< z_+>fCZva#4vu>|!y*^wJ6o|2qq7@MF(5BY;rDe)redFs~H`MWW;QyPGcTiwD=wRm`?GI0*}HbqfT(S?OFqsTYY=mzu-tU#R9*{*+z_vL#~b&L*1zaQ!);$^ z9&A$cdZqVCYH|?NN~ppt`A@RTCWaoG4^E!F)|`p6Tjsnfc5PW+HfSCULcvm>f9#G& zb!L##C52$~=ieQW;RsOk^I&;lVLH(%(kGJ6HrQ7Zds!Xv{FcU3uXLVf@cExqfY8VJ znt2HpRZt?EGjh&c3gUl_Pl3uJ5Mj0btO8N4kl9<^nZOxa7}(*7U} zK9y%Ds1V&Kg5;=5ZGz}$){FuMJir5s?Y7M9mDTa?+Jqt7O3lEE#$O)f%T>Ykuc0he z-(cQXYi6Sxe_t1z`ES|{O*aBmn0L<>d83(>MpOA$4w^e)Ncn!0q@~@~tzCTfzRq9s zk27V5!}p$@50~Bt)GweSft`EP`!|1c_9>An&juKkzo^^O<{#?{+5BnSUfQe3qrE;q zZg+EA2BfdnDlP&2H5-UB5C7Icx%f?Y+lOoL)R~(`ebL-bMZUH1DUICUXwAtSm=fLD zUt*^qb%ayAPhyJ#b$x>zqh>?{a~;xCbY`9WRbYieIg)x|B+aHA^~f4=J$3DS*ox*|M+ePg_VUpapLwQwntI>HP8s0_prGSw1GOMGpx3tv-cCc)Xh z%b>F!aimY+vbV?_#o>Gyk92T~|1dzZ>n)U$CbIp>QS^UM0RLm$MAh6q7gv#>F*Ol zxIL+9b$Q=E-ryde#kJ5e^WX-g`ee;ZuChAp|ha z2dVr+L86uHKl3y9azxo>$f7>sb$Z=m<=c=Wf9dL=h}jO4%eOmf z*mk2Ih2zx&f1EZ&z$PFu9ARAY)+&oBM8e<O} zU6&D^Rl*!y0d4M{tbPM~M_v8%eol&w#^y69;{o03;kIog(WGgW6-c|#5CVIO2-iQh)6f<;FRmas@|Z8VwbvWa^J+T;Cmu z$92fPcHcJi_=FvBd+bbiYy`91whFjr|3ffgESCElr0MrGsnHeugwcAThiA7M(%`l? zxgs>1qc7g*ZvPZJ15S44)Wik18dmKEwEu)EpMtI}vnpANIG{^IMFrFdnB?usX#o<+ z99e>-$(Sm*{v_t1o6~Y%;jejnnY4t6Z*(kVaLQ?Q6n}P}VOLwAi1a%0=ViWx`OcRL z4^eoQdP?$Zhji9bRy!;WW|&uf)ev{AtB`d(tytb_yw0rBKZ97z$B~F-8X4KE8wmj9 z=G&Hw=UX(cRy6xP1zwZpzI%gb#2#-x<+WARx6?a7 z?G}Fg%-8gYX;|pRA#X6b<{xd0oaiuum$i@bVdA1`@%4k>kBC3+ z9Pb$fMM3iiBiUs72mYH6k|$!RMf-5XKCwFxSUUeC`b8%LVN}F_(@SbzOq7oGqV&(A z$8#Ux5eHVN&kyzp!!j;Wv_O&Nk^gPY>&j)2tR5pUhDO2Sd+LkqI|nj}zUA|IXP%Nb zFuEvGd{gU*A$65}!c=@)5!>{4h-GrQSfa@nVVAh)Xav>BJvh~ebxL2I?O)$RPW)G8 z5)bM}#=omqO)wC~54PL+OeGZYQHwaL)WW9>fxkRVlPYqW%6r^MjyTC(On)8Y=H<79 zrWr5p0;)_|+suA=_=ilGKvAmsz2^PhjI(B_oP6`ufmzSpN4XT!dVF)A&z3yEk0Iox zc&oB4$bI#p4mt!Hn27=>0aH7ti18Y2rs=6ZsxFSZ6_Wxfa#Q7ld+1b2U+xl(E{t+QLz*1 zaCoa1IrQ_=4^(%Tkt=L6Y2__$J0*lO>?j^Q!RT_n@F=C^BaQqm#*dF4ySdWIa&Rk* zNq<(@@c%|V+s28i=EU(z)F*MRs3d&+ z5tVm-1Qa+Lpv~>)1u)g4>h0$$XOC~nnG8#$So0P|wPS)soVX-?nzlBqLC9j0^S%ty zXBFcv;2;F1=Kiu(Euri(`4^E)MvMVir?4}@6Ir6?B$#x2tOb6y%OP&nPTr|UEXbcR@j{3+)v*3QaYV(^2J~4`6Hl9zXPpKdMr4y zN*V#~l-1U+lHtKfo3P@{x-T`ai0H9x25Ni9tQ`^iOCNM8-YoNi{#@Ndh?N)=acNjU z)i!uMTDh-Uj`Q8iSyDtu|8Q3x>HH}XIh>#v4&?Isc_sx;kzK}6OL|SxTrsZVD{X#v zVOvA|5FHS$9xSXM?O%?%J>ueuD^B=s47g@ku3M8*H}7+khE@9Q+B^JImIgCW%e zKgJB|xmv}?!jBMzN}%H&#IVblaro z6C!}i*XyrphU(v9W(`G8|E%a_=~$oSrXof^RbtnJvSqd^)}<0f0X$ zhBt6A4@lLk@M!d;pQV4)NrTDz8?On(gi1eM{ifnG#G{(@-DHV|1Icy(iz#;QekvwOSqJv0{=%uq*@`jW;z-eM|G)*QnGCn(! zL_n|l3)P2x&JMNh|9Np;5oLoK{O^&mVjn3yNl~jDPRvM2X8m zlQ5U_3Mcqs;LQAPI6Gqp+(8vBSrJd<`kkWZF~bZ-WgeV z%CMLb?lVPpOEY!e=hWXD*%%;gx&N#&T!xK##Ef!?ygp&7R65q;qw*P6c_KN@Zdz{G zqo}pgs~oUwH4R%6xTx-4dHUWg1s4dJv&_Q~ULZROwXV=y6&5d|KB>i=Z&Izf%=Os< zsW*x@TYonK-4CK>lz5Y;a zHOThSn9qR@_QSrnfi`>bXtMA?HFW8MSqn^+pnHJp9W0^<8_8ZIG5Xs5d{H=f=(}ME zDcQhJT?W~lniV4O(k32Him&{Qn~FNUOY*^buzx5eCT4cgmfd$%$X$|#L|i%jIpgT5 zufj*|*XscGt*%H|V;&hfC%)lA6~+53%leJwL*Zk*p`#cG&!p%ii51XDCACNR)0#I& zl-a}DHCl=UBTbH23bNVS@BS{;?AZjG{9~dO=(_8?o0!(Qou{g)P)TNqy$&6;`h@LK zXcsLa?VcWIHS`@^T(o5R1=Mf?w6i^6v@*kzFF5R5{Z|MlU3g)wZz{A znqCs8Q-ws{WnCars}Sw3@>ABQ+=*1Kr^6kbq@4{j{A|e9yY_8?F%#PsPZdv{WuMTz zQ-18cYjg#{TS+LkpTDm{C-USFpY|M5)40YKgH5?%89PLRC7B-`+tbz8)~WY)>;2K2 zXAil?1K+tuVGKOiSw7}HQD+GfyIn=CiuZ$wF@r%|%9e9Ksi>ECF%;>)eINMH^sbpK zltLWrSP3SFG(q9k-@k{5B#{ zEe9VCsXt~*Y4c@lY+iu&a)(!zDu0`6>u~3yb|?9~h-xZ4*VueL&;kTeTwLzjI_XRHi3_?_=JNsRrq?%%ac9Gh%0S5$8TBj?55PToH#xV|dSf_EM@kAqBd zjo)~G5ydvclX!K+D_o$9tsF}}1g|26@$Z663OSBy` zZc`tOfRt#jCDJ3G7gSmG$Gb5+(xrws?;?W&82qk7TOu_3PEPxear=E)k2LXqp()YW zw5VE|NoLi!=J3t1UAObzZkbzgTcvW&J~wIt!Y*EaSRn>+ru;j0dyO4<`EoLaVs!Ha{9*%U1UA;nd|_u%c9;=i^Kc1)R)1Wz45g zTu)rYRg_)%gEYUPMvzz|J8z7;=cwjpDQa9+6kX2F8dGKv1XU^Zr zDG^1`a`OpqhvX|y^>NovlHPe^+wxy{?`u`QIRe&i&{!!ZU~cw*e|yb?GvYSR6L+Mq zl17eA!1-SgC;&&L{ga5m0ZP;|4bD$oC|1Ld?_QzRq#|p?d>Eu={5Y^s_DVMJ0)LIi zI9GBl%3nxl>lZ@l$VS`<`>j>I70?XME0<{K<{>1;SA*ZaRMh#L+=I)Xb@WyOUiPB}6m@!K#peaL$VzdyR$`s?=(B_ld+F0F1&LUH%PjK+z*<2sAS*5JSg!B*D= zxnt&s5GpoLQug5oT)BuzSH_(Eje&bSIqBv&FjJ?=m&G!8tZ!yrRH&uY9w)M4mz#8% zR6*Qoc!Vd+X=!_W&T^1nJwN;Xy$c`ZfjDk2QJ`$dZjiN%m1$xqB--Rd~V}t=_^6!Wp?@ zClmDu$VOE8`JYW~-z9Q4q*dlNF@B_Q<9DNtAL3{4IOQDTOBQNp`M53ezn%z?;4tTn znXd!@m`%%oR|A%azTNRB^=#q(EyK7^ygb}iN>Qj5##XzAcIM+s+>e6ls}lQULmQ+Y z)Jb(_23ffuN8@59U9EkbJDhyC>aVN7P8yzg{iM`sWyr$uCP+~ESmRd#$Fs4#fY7t9 zo+fbtv-7pz;xG0lyp3s_Zod4YfK;HESDJbTI(mj`0^yEdxd&a^9sY{!m|u4WE6q3o zv&U8#YC0*}iUFM(RR?iZ(4M7bT*y9$-qHK!=mW?X`z3`@;o_2cv9`bjUaDsX^9MIM z1kIA!ywjBJI%55KdwTV;cu&0fKEihoL)4>YK6*qfl1Y%m#7VdPl?R)X3Q6@{gXE&{ zUU`(mJuP-;8d_B(i)TY*;apFj`%c&Nla}t`48>cYW323-(^uiJtk!1GG)s-CQ!dtDW`%du@3UPaUCC=d<~Cj=8Oa>&B6SEF@*nqBv2qMavv>jhyCYJS(L19wlG z#$*va9e08gh!4OQkm~_>*B4$ z)!Y>@b8*DH!-np*S&A`Q-erys38%6Uo;T)VB}9(Pig7ALV9^?m{yqxwq9d1(NdP6k zGehFFMs`v*m+Q4i{N;sAROevobnf3&+s zd`CIJ2MCZqL`oo>Tl=bisF}$h+>OYwg}`e!S8?v*glqw}#e% z$+I)TIej~nidiQw1GaxNN8QqTq!Ni1TFr zQs3wrQ@tM-vHF714hZtRl-L$v7_CjH(e7UsE@=_Lc7w-q!hJ?WkBP@<`OB8is_2b> zoAVI9rgAZ4Z>D(lj>-?^WWPvB2d9;Snkm_?Wpy?V;t=zHMXUUru&D4rZ5_Pcn zrGMm3c+Ax=GX1|rKyi8X3snv$K>Z_4UtM(0&>!TNsDsz#&id>IE;ZtYG8U&J2_!QC zi>7txc%${L-*FK5@wLAR@x%$-MB(A;dBlmgXV?>ASd^parb{NY3o9D4MxO-*2X+Tw zK1!-b;a^H{f7$|;F;8>y{-J33fa^-@LMy%2_PXB#4&F%qKu4p0KwUAJsqt7_;3&*O z2Lhu)U#re#g2o#7p>w|agUeL3wV)FHikGx*kP%E-*!L5?P=}t2A+pHAbp4fZ+nrS+ z5=5thDYV_Gtmu4b^Fe1}jrm#n%8ZeJ_ps7lxR+rX%wJMl!k68wBQIR6{-@m)T`F0F*=md-7} z-T;7Civ2|&y5;gnRM&Cr`zFRu^$MaWgJFL4qyz85aYl_z<`}hld|a(oz&HhY6QfekEVzUpGE0`-((X=-N@IJWSp5A95u9L&@gIv}sd} z>&fAG=J^;^6R?i#TdlX<6k)Bi6Y0Yz-XHx4nfzn4O_?|^Fet;qO~f>peO}6%=t`u= zZEtfH*AY0xJ%&>oF@G>BJl$LN-y!b@@Dw2{KLU@4j;iv~KkX#i=kr#=;RKZ>5$0Y& z6RXxmJ@El%O~^>O^B|C_yN&t;)Q+3 z$5ULmfSxAkE%VjBw!cP+MI0^nc@ux<9uOQl-4#htT^gzBy!PtCwDx-FOYW~2qbMoN z5MQ1mUy-h7A-H?OxawDLF7*%L{0QXrLv8g?+FMkYl3?6)NBMHN*KB3-Ebh2KuvDY# z;TqL>FDQ2Dn9KFq9Z=ebL)B0JwqmH=*Y4;qMKO}m7GBoAb--b$S6egcyGGIwURk+~7>h|hxWx=0ne2xCEor9mOgcX%~s92rGsLes>a0uxx=WC@t z_u_&9AGZrbnm2)kR%jUl#G8BK01yYceT|87L&D-c_wak@bd?F$sW~Gl>k@g?^)&qSjW?B4FM)DRb_0V=PG5h zom6$(gFo=H6tMu-zzZZZN_??sNFggjC&3Z4zszrNdrLw-AoXC5haCe*F#fVn3#M`Bb%O4fuk|Sw%<@x`CgKt>kNERB?aEKC{BeH<|ka(4~Mz zxsPj74x%b*ViVT-yvUlS`;CXVOr3^J?@)4wl+$Mg++d5RP~$*;Yk=~oc0sdy^0wf{ zONFhb%E;#rcdGD|Z*!KwS1!YCniNsoYK7OY7Hp=LBxHo0fcnDt#|#b7T1 zH7L(TpgY*s!h{xxSH3#zQJg=2-)*3t3SOya9blCMPbpuoX{5(R6)r5&E5%2K8qv38pYe;6m1LIrTWdL ziz%uV6I{AmPRXJsh8^CjHM%$WGo~A>*DNn=B*Vr>Ar+KQ<%>zd&W4LOaO8I|%Sk-0 zG4BIWIZ`EqY-S_UQ6xENHU_KVbuJ}hM(V!`!1@<#_@CR?QM#SOb(JiLQ?f_cU3qHlXymE42DGuwk3y1 z6-xHnmhA|Z|0e;MQHETiyIlpjQk*a1V?_!u%(2(zmJy^gz`Z|=_r2MMnkP)8?d)KZ z32UqWF^#c9SoqN%e;g4-<VpDy1cvq^MoqX6H6K@ZPushVb%wdy%Tpf0l9Rz37^YYz0lQ4lKJ~2)e0}=`-WyZz`)FB zrGW>fYv~(UXgBx0+2NTyAev?NdMey3+9@ee>hJu4S?v9@RSaw{azW1XDo!k5a&eJ> z#Z-m#qYHU;PNC7wt0^Iq;U1l5Z;x8XT_LM)cNKPyFY*Oq=g&&PEB<|cesnIn02I~Z z2RMi;-;TrZ*ipU%#1iI%(yo!NT1DkcFhIj_dt5zmWBQ{D2t@`{Z%tFUgNqCFAy`}8 zDIFfVwG(sh01`ug+=GcA5FA}v=do>Vx$t85yWRM75|E7oJS+OrN|*7+H^+V;16HH# z32K6Rii@w7ZWYy6aN(g!3StFJktnoe>}YxixV$v@#fbV_6U_@NL{ne=3zbD`1LFfR zM=PJ$nz_vQR_&9uj4fBj+gCPe897nDVH>HUr{0YlGGt}?R;R4(9IvcLuRrZR{SOR` zZTiQSKaLAAS5XJX!9&?6FeTo!n$v#y>=iCy)hyT{Uk|0@VSCF&+ILNqLF&TMan?}K zAI_1`o z6+hD6P4IrQ3##)VJ_;G4 z$=v<^z4pWlS!aadysDg8e-yxWXVxPuYY_G;Dn3991$8X3$cLR)=vF$MD&_U0qqTn2 zm-A9_#VJaz6u!I|a%aF?T_5Q|0)2G1 z`$6+tJc`}zIKT%(cT$!xA*wTuk?WtiLrMx2vn6NdKFXDVM(5W1;n{uc`hrdD`KUv2mW*C$Dd z&&i|2M!i@k396)$KE9NGBdHWKAH`||NXm!MsSVk@54V{}u*@SXWpE`NwG5?0yMZQf zN7u2F%4`dM#Oo$iW?`%REHbg>h@}39vLg0kCM6xOBWmTX-+i!&DD9NSUP!7C5z!&I(mS$oQN?Pmw=*P*LxS!*ME0{$2|mzpJ4 zd+lB30lHo4&)ivePTaNYF$k*I;)>6c_2hilgu@4E107a@zVpYGP6MxnOy3co_^R?3guSaQifkyzfAAol!}pFPek=+;UR+?{u=7QmKhm4qKFGH597na3x!43Td@9 z2WoO!zgsXCyG+TjO+_pBpi+1z@wJw~FR6Od+_V7tjvi0l{fT<9yScsbcVXnp;(Alt zi67>0s8$8O5o>%wz9ZTj(oMk0>=ncT9I64m}&5Ifw zS4iz72wZqMG2(7bGJ}sc(!<)%jvJY9X?;g(&D2_#QeU)pXo<4MAa>RezW36a#??MK z@otKw$rTg7MM3L1=SP3%T&_K z!atHA+V^tXIXdqzZCcmy%-2r^pn6vBZESMRVAV@E6Xms)aNh-Ew~014)1PoeiNhj+9Y)DAec8Ql}J zf~RGp$hrhI)l5l6ff>FxVyW%yABS;-Jw9~y?lK87fw!+o$M!Td7=C) zi`o0Sd_U?E1yxeCB9oeiUiiZMJ8IaV@kr3sKXOBV5Hi|Sjy{wN`$)(5n|(*N{UObQ zw{6?B&N{}clHal@4F4djK4+^XKq60l(79U?{cA^snWKFoo3AFBTbjfHH7%Kx3rmfh zI4ACRrP!ln-L8m>SKa)9HwK?+aR(>JCg3@SUr8;~J;gbEF~X(J_L-Fj%OVYS{ZWJ~ zI|Nz3p@dTePU^q^KyqzxVq&glX4(z8OgIBYgz`i$&?rtHx%`B$g7@RG-XQ(7Ak4qe zB|o>xw!jZuyjcj)el zu>k*14B!L&);m$ZIIFCD>!|)<#5B2bzR$G0H8$wJs=6OT)2^2~COPSs z86%4`v}LSulRvNNm~Pqt#bk__e^MqI+xWvp@d$eUM>^=}TO{(nulq7t2WeY-@lo+J zLJm}vQuCFf65%tHnC6)vHK(erA(o#?)}9eHC}Ay}C)O$M5Q`%M67BT}Mz;yVssv&L zqKvuz(kYy_63PMoj1u9(A~Zj94wK|ygRf2GWn+Ih9w0QMx`RXlWJDTBOVt0n4QRgx z56;vEclw3f{c%m9-_4&&c(>QU^)S4ge=MeiPgCs=h{pG8UNljuMxP-muEQFO(vimW z(hSRpkx;sVtFf^Q*XT zDXOur1wAx3Y@afq`ue7qQ>*w=Cx28id+t+J*LKpk1;6RLTu&FA+_e8lwLIzC!>efY z@vZjxG=+3~_ltZuM)7#NwyW1#Yt1Lj>BkCBtIr*zQG4xG|KadP^7(0GZ4^HAV9NKM zQ=VT?v)ZDIur!R#{laF)%vfR=QTjXeha1oQxu~Lz9Z-=1s7@pI=pM7=*ifF*Qluke z?$pSkTBF+>JxkVH#!J=;YgsyI+Dadl$aT(%Z~u9dQ_#bKUZ^Qg8YI|=Iao;;5z^rC z+WTe8qJBBP$s;9j=pM%&TKnr% zEY5T0?nEM5IvU2U-W@F@@mxvRMPXn#^ZiMornSKjQNTZSp-!Z*-Q0zhv$dHSEXTms zqErgYDfk_-owi&Afxvl&nv1cHD&nS>7XttC4LIleh*hgJel2ogQcuHMG#FJ*uyOaV zZ+32z#M>X)ll9w-%KT%Od;*gV75=tO+-oJc-X;?H)2Y8zuXL47He6YVek ze_he|jqUr=9vl-d*0#4u+PmsJHxkK}i-8aB2hI-f=iKvOzWvha+v2=HZ(06EbsuZ! zPj*I{)#jsP8CW@yrM}$A;#_lr>nmTU*5asnCHa8-w%+s-vr6^;evIl^*8d`g?a%XH z?QSt$k=i#}z0hp?yqaGp-#^-eSrCc>a-XVBv*b5Yh2{H1`Hr6|PgdQ<>l3#=iBvHUniTO-8k$nCg`Yn)j=tBGOncR_1KExCYJ;c0KE2_OIX?rGL%u@lj-cl;;WY@23Tsf9ZxFU?`)M?MTD3Mo4pu z4u()61fyj4osxBK`%2YyRV)~?*sPGu3g)oJHKw&SJ2LcgPh}C}3}O&Oc|icrQzK zElPJr?_ro{l4Z6ANqlExbV3s>GL3K`t`c#Ie%@~$ZGyC9Ua8e$qNKRs=<`;;~5CHs$o8 zlFNZDyYZi2pnd~F4A6ijaIXY$1`Yctq{-<%WoJ&)BFdP?{oXI?jnR|RChw~>orsgs zZFQc&3B{evRZ+WR5YjC^Qi^7dn18sY3{0#CURQq)UVMeizm;l+G6EsR11DR@#|4s) ztXErME-QX@6YlFf!dezxolI`-S-z@QY_kX(9?Oofy(x?;z2B( zX1QNOxr4uumv-+(_tBQOjuE?6?_tLgtMHK_SINT)gk>kds2u|Y{u{ahSgX!Bj;+{M z^I=Nk-^VcW#M^n6eOCH&b~EzzO?!iaeN*t*n(c0=-~>VWE1z||do2q5%<*N>@k`Ga zm#rR)U70)qw?m5eO3tlSzEYDgOLuPz_DG+nzALY>QSrTcy-;q}ORfq2Our{3*HX$u zO-!NJ-5FW`xT^r)jC?OJo8OESH582r^k8|!^+8JK@t4$@{2piY9vh`ow(C^2z0#MK zs1&#Brg~nQcu*zqcxQ5XS%D~2TG@yhoO^_etvfBz5TvJ72fGMt;52*FTWj5#q9s(h2LA?2*+`q0xFCc5O|&t}4)21*?W z)WW{96jQDf9&<)wf_+rtD>W!4_#`{zRHdr*uDfNk1F{7^8XGP%2`BHosH)N4dvBl_ zf0Oi$+;u!y59M_)P}KCXK6cp8GZr+j_LTm$g4ZeV&;@=#cUb`^WU5TrLk#oPD_=Xl zoeT4hWyZ=BE;8JJvtl3C?-d`GkM1H5@VN^z{u*@arVo1VRGsHVm0s0nO)7z4yo+o3ZwLYR6vy>DD?N!~g4rqX=4nW`NYp z>O#Wh9(K>;9px5|r0(?z?1N6yc~yFwQ~bQyD(Pdlye zUbCw`huw`@;+?tQQmwZ`?Yh39yUj{a#V%>ZV^>;YKcYyLUr=Tsx-kG0;homKQ6kK{ z6F*hw^x)^8reQ0*FcQyOeojSw*Gl+)v9wG6x@1t*yHO_t!Y=&fEjof@HGq;8Dl*d(+;0^dmDQAc%id0-8t98{8!pG zCh*Kl2skKSgGUBFsP%VUdJ;(YpYm_%mJqw)kkUNitkwz$I8?CcZC4L8fa)9DTyDj5 zpKb!X{x1Cu?T)g=h$3-s5E*`?BmYDA=fy>2-~>X@_Ehja5ahqOBpc7)RzPb#EnHiu z#p6*+ZbqZHM7YHkYAov0JlXfX2{{w_io*$kg~zQ{+dkpEh?L7Lwvu~^jv?GBkHY1h zk&eX@`ac-c%F|63eC9u?mUTOL)W38ierk^T8>(~ER|@kfTd~+ktONZPe1-aC zGJa}*<|cLz>>0p>e?1BRPg~JxwS*K{mRsYx5UzY>Tm`WS+aN3dnTgH^m5RO6sxNkBArvcsYU@juX_u5 zGG~J^OY4iGAJ$$?PA6%N0C}TNJ_4s5C7=VW5@NQ|Qe|6ZYV;_y?Vt}>dqnzq*%W1< zQkg&hVEwMaWPmtqZ~2?fx_GlGy3ZVcdqBIlP6)tvzMOq=T*yqlrP@QFI!nrL&{wYDUpZ6{CdV;2zRmd0Jhq9#7Xz& z>9ZzsRm_sw(U$J)nzhtiL)(@I>6zQ5{0mXlmhrcDA-rMgeQ^^`O&TYWLM8}ForzTc!hg}3H77n~88~~9eE|}ucZmF^kS2nHXhi5&{ zkiTAc4I$KkhwrT~RrV;P@i0FE4k$}B;z8-E1-@SOIy_kb5h@vlhE;MRhBB8#hv~%6 z2Hp){w1V1!yFsXi4lPW=%@g6hS3i~vYKBPaieyy6jlAYu_PJ8L%mh$d*(a>eOMB1p zWMtC3zBC9^}R&rCynY1U*%8l>`fmmvPSwH819Q3UTMi`P&#WR%xDg~ zBk!JrUH0FeFJv4CU%!5b|IR3|;-YRC=l<|%62p#OlC}=(p?L&Gr)kGE{0N2j>*RK+?Z|3JrG4ym^3ZxxB6>G>TGBOD<`V5|3>w~@oV|7KUg5@g0Msb*RAVq(Y> zxNISZLyRR0lF7n1sDb~!`wH}W_!;8WH2zC3P-}R^IvEyagxU2A3Z`N8Shw*(;EajU zk`+t;U#U+fMglDvZFjn7?YOiBz~#PkVT${pn())Nj{B?2Z(hg;Z;Jk>LQN}^Pc|pYu;jKE1FXiLJpDzoG(L${ZgC@x z#_&#f!8~?+g9s&Nl=UJ@wI~s2)SU`o+uPN_RC9>N@{+d(lisiFhXvCu)Tk;6X761| z*LVW@6KqXH-3cc9CZY+!=$%!rx>AG9K@#~~o+iGg%wUeZowP(e{UF`&Roy+y_WKoz zdetvCn^_`4NVL?^2vHlgW=uw-U(=Nf&u)#aa2T{1!2EDhPw;)QQDa{3P|q8Iv@ALj zE)%JLVw>^y3mg+-0POAC1zRJM^h860hG!1ut1gHDDtk07UEfRCGH~B&z)ii%r zU_tP)+*6hLvGp%1>s^95NL-&~qCy_X5nd#=<+$(&WdX80%ZI%Fi z!1rA;=6PzCWl*p7h-$4u&`APEZgX1H3GT;%!ZW?;T&sJPvg$HPOK4T7jLuevpOXJQ*=9 zM(}4eSaCRqUB(D5>5krwlX;RM36C&*C02Eu#3C#0&e@bVao;EsEfbPy{-NfD;TH!* z8>OO}Gx3jqR_L)>re}afD@D=l#;3#1FDe%CQ;GM?NZB|}ZfqQJO5x*m5?2UO3QjWN z65zJ%T1J0JFEq)tB~O}1$jVhZEY&KL^p9P$IWrNReyNG&lQ4F=I;uvv@qxBoUG1G)*vDRZ$Ga|j%4EOiYuwX zoABf-KL;RS&8||Zna$+>`nLed^R7q}^87$bn^p!NFSw@v;n9 zuB>V3qw#<1tg9-eeYDm41owBl17;;zrbsdAJW*R-t347=-+5K7SI4k9VddpJY5xjt zRzzFGDcIjVBk^5wTfAH20~L9-^4)9%2K>gH_&Fq-_W{r6JAtM-8U zH>z!-y?1rU2&+M(+mpTlf;Q!6dwtvTsVi%-IXzML$L#*x8(tCXZvv}XsSV8PC_t`C zTSI@trH!MBH9d%2RkMabXb+)n7k2eh^3Nf`m4niF=W9dlDp<+u;a260WWWb1t{h4$ zv0bRoNXWz#sZk|v!#TFv4zyWhwLWn9B}eIQgv@2R2rH|$8;+@gQZf};IO1uV%fLY= z%AA&OLtY7yzSEsz##AnoPw;jWCkK|;$)tm4Tlj|mP&#~wY=hp#_$Gx@t#(W*Quw%A zeyGRgX@w&;=;Xh9FBLDMR1vfJKm_VC=#_NpEEQ;R&}@5bYW64t^G~m35Mp8ZCw$FoU_a&2aiEdtsI4NJkyL#_czA7Q z%S)WWr7~P@?3`Bi(cScw7HzB1oDxI7@=GB7A-%tchYE6v4xTTHT4hG=(kF%c0y01` zhFXR_;|8o>y`|>a(@j!^M8mEXOR2$kn_g1-3@JuCUvg>u`?S-adEP^pI4)L*(U` zeehH6(Q}ry0=?y8VU@!t1$N3F*Q3Kz#7}vSqJ1@Tb&g1`nJGi_HSCOXXg8SUaqhkH zW<6x4**~g$=mb~bsv7YGY_4D4gotX|pzHink)CUEDZz*jh12_nI4|r-ivg9<>T>rn zvY?lwR7p-E5HS~S&i=8#EX&0ywF>Ty&UTo*cA-0jx0DQlXMTQ`j)?sGix0?;x$X}& z+Z(5&vDj1lHU&Ei5?2+4Ocdmza_hHO}c=n&7%8`9}J@uFN4V zeC(}Y$&he9%WzSUN!PB+OZ^YAwjKKw4nt6Y#k=^-?n9;BNM*rC5ZeD>OcvI#!EY!p zIvw`;lWXS$D-~_4(_tlHYSMBY>%sPVQjr|q*h<*_usMR56wqXVisMWgG@ccD!C7&i zr)?jA^E0@jsd~U~4G)=)da*=m*5}OO>K$X1lTFpGb7CxS1X{=3R4)DLHluq*X8jy^ z=Mz%fVSX&DzsB~SxPZ7VDXyc%MJX!+$+eepg7j+&T1b7Wqu)H zDekw4mVH})B;e-e%suQ)0bh>-^hMCI!+7pb-^hmaB$1OTb5UG8j!9km(RuTFDm+pd zIGW%@_6rvGA_H{rj(fyhCh*+~d z4oez|7d4(QrA4l9 z-}P`W*a`rnH^oe>;!(IGpBp%5dNnd0S8hgp=%+TmWv^pg@~iDD)0Av8Zy^ZLhZWK_ zxJboPR&LC~kU_9tTcObEf07fr7$0u#?kzpmN3dGw8`+QLzb{#E_)&zus&8Qxw&>vy zd|VNeelX2ZA+h04v5;lCEcibdn~`|~j)$#!zXUYa^U%3SByHVw&*W>N9;bq4if z)l`QrgU4wDtH{Gm(yCG|uyr*9&UlC&e}|e)UY(!~KhKeCf~3H7WA1P*VJMuw+9#ih82s-gXFO>%VqEDFyhJ)JH9r8BQeuyYIrPqP{@pSN z&vBD{Qjbhs$xyUk`zrYsdeIqY7i<=Kgc?LMKX@y#Is#p_K`jYAzlg!u|_sAf5D2eB=rYMDmgYOW2W(!0L=;m4!)#8p>V{F+L%m+v=eiU4vvkdy1b#%hy!Ue4a9_Vj`vsxL6OA zN2;{!f`QZUAmI*UvjIENt8^~EOc-e}V0)i@ro9&1tAwG3@GjdJ?-Z?PpXbL6JB*y{})G2Ktw4 z64pUT4F?y=VanWgQ?jlX^P4XkOV$E~wn zm7)>DO!p|`ZsQfiUL6B{0U}H%__xMprB>fx>o3pJ!f<6ijq|+qZ1IvhS0FjCbU0<= z>z(L{S7^nwnmg+~(23eq`Y;uB2$uOQ_!z?6kJE*WmpyM-si z(Os4MiKjB$j*@>_Q%mkH=$jNk=@&4&f)=I|<`DRS66P3oA+^~2E1?#)blwB=X!QF|#I+X)n=k2=1|nhK4w z;xw*0Vr8dGjHA_+OC9_=H~YrG)5a>a`?J2ijk~=99NDYp`I2(TeUx z)6M0!)%n9khO=5vu?$d|X}u6B-EQ`EAF+UzYw9wq^Vpztm1`ELS2P}iJwR*Td4T|x zDRW6}pRhB>*^5+({Bv*%ilXgsjrIpq>J8Rl3C&OV!i)ru*D{yOV_(iBC>qFMhRK4e zAHH?;1YSeX_)i)Qt0 zy1qYQLlg7GidOt6Q(CJ%;o1SsoumH|2~<@MlvqrnB!->kEM(97kPPKQNv2|?U*%0p z&Y+#Va9C<|#iy`;o9K*~<*BYa+QR!)?OTb%tgZ;Vqm&$#$#jMNga}lPg%>9@5=SBn zkU#=D!&8l6r3EpJ&ff)V`w^%pr}Q2p%Xa_D?90r01aRVr|8D)0qB)~yPLh@K+KnE> za7fif(W*TDPf0~Xos|ghI;vLUppN!h zJdTyCkxaPsGLOx>efKNZ^$U5<(6)S7y)aMP*29TX%0Op{9o~LKNF>0=Q>%1h3zscv z6lgVeSoMgtbmxfy44p<_$u2ZPA2z}I{32b*BPO`oiJlC=8mL2+`pGL&IXP$OIeA5n zY|Bvdk#l63d+@}cQ<{(Ou96GN<0hAtbwoybSU`nxRL4MI&<7)&lX;#uEgtibxl5rn%Ym67*t>&=YUmK8l)(bJ7|k<`S2;tWdC zkO~rMIWT0Ax<6pc=BDzOUoor!SKGaTHG?Jg>e!?tRtk+AS=AnzY_Hs|SY178`yPUDku*_@daSj@!cOhj)%K(yz>M1$_@+-!>kiKK^#_WH?4epeh0X5T zJO$uv*RGTsl|01nJsu4b9 zwLZ~43vB>sC;jno8vP5D!MQW46)Ie!gXN1RBpP4RjmY>TsL|Bwz5jjz4#B33$HaYq z5ir7AqYr+Kxx0K1dZQ**AB%iFsw6H_ZxG&@Uxy$0x}x5kTpU&=bpbBYJlq7%y<5Nn zvL8a%7%t3G0Q$I$ASSfs`8SU;DvR^VrmfE5Gf$34EL4?GHK)?ehUH;-4@E(q7o!=z zU(uRZH(Vy1vk9CfMZ|`2$>LK@?it7gcZKMF&|wQ8`|p#%w2~poy${Nx-3% zW|BA!G?*Eo&x&B#@x8rDNS>JAnOoS`DAl@lpM?I=-z%cwAnw?riYDmmi4OXYW70s8 zJClfN?!(-L%k<y>98BGljHLNRg|eXZ+S!I48O?s-{Tkd^@jcvbXw^JZFjZSiJwP z!w|O!j@zcVDi}z%I@icBByCeE>4uu~w)dDLUaK&Z;P&qGFh)8Ib^O^Ok5gM0?#5v& zBU*Hz3w))dBAr#^s}Ag{PH?@=U0(T(+$02t`HUoxryf2q(uZ$gSposqg?}FR=frQI z4_oC^^}^8Bh)!4icWR&|%NP!d-ze-(M9I^<%T1jD33z(4y8%huB1r>K^`!k&= zy6)_LBK*>rx0H*fIH>VT?6S$EH(VmH2u{PU^1u{Wju13STM_sHKiH}LK%+2F$NZa1 z=-F!*QVT2|A~#rG8{{>7lDTBqfE9XP@F!ptaYm5mphPF^V0Z_yvZTsS1_M4?p;{I3Vo6Gdkz8|u@(2B5 zwwNs`(!kOtmBVIj{2N@uL@q+!F6=|aTTv`0VA&hXoM86!6ih`1Yl&>w>6S2D zv?cWd%yLC(W|A6PLFq~Zt+OXm!q#xZbY{B=?&}(XQZZRPc~0XE7wO-XGYJt#9aWEz zTI)crhX-iC-|;h1QDYQS7vCq|!_(&yzy&W+^qY5~l<|l`~WMmuyjxB02Zh2P30vI@KLFIh1k~y)7 zbN~3JZ~)6h(FQs7pFc-&7RMR*Dj@-&5xu@=m6wa3uMQEC`Dl!~U|l#zQ`E_~h#Sdb z=tN8r>}2LKZVGaSRbR7@EQr?t#hedc$z_|+8H4_`Un5t)DxCg%UnT^9MAthoAzWBM zQ;Vi@cZD<=(KuGFS2JCeFdb2d5{p(9^!4{bq%0vD{i-<`nJbAJRON6NskIM3_#}Oh z=)Te!9OX2v7@uDWjFZHS>iln!l%T=3YZMQeTijK%7^T>UrzQM=C$}&Z43HlA(gI-> z`b$ZarjF~-uZS0t^z~PpDG?>pBZ>J8VpV={{A8ZES>5;N2zK&ps#V&irKa&J7v+=3K(o`go&JZ zt-QK=z?hyed-X&Ma>ZynP-^2v0et_u#=btKmC zJU7>J4x&)McVxUlpmLoenq%e~%8n){a9>fTvuMC$0_~mO63RXDRt{KU6Pkuf$-S^r z$o#^)H&QW03ql{s3J3gr{m}VKGD{FXEnGpvl{56+rQXk5X$>JT*^4$!A^3gXL#Q+` z!23_bRvp0gb?=DG_4)ucmfM-j><{xELRY1X<5&?jDhko~A^aLTr?w&@nkoYpLP6mx z&vJo6T@0S5PzEW&{9sk(oczm&C~7FOFnkO5y$>|q(q)DOdDv^R{5R*dv?}AI{oKne zXwX!|ZLMjg%$Lsp0wuATbg5DGtc#Q;uMznqF^IlNJtZAF8Lzt%|JZzxB~`t~yDjI? z)z{WMG(tsVzHGBtE0RQU#+u4ODMEdL7eQqfmq8Y$>H)Rkp$D%!pNH8J%@-u644(s2 zTzTI7$VLQp?pjF?);lz^TVG{4%&wKZ3#UO%KhfDm`$XMQGS5OB#lng}MtzKT(q|Nun&$lOt1R1+Wglv;7Hiw;JRC) zFDO{Xq*q1JYc*}hz7CO}U&2SSk^|ryG$eQ~lPjXaRoOzbq5b(!(gv)>-7Pn5{(&Gg z4tgJf0pCw4VdZQ(awC@&#cbe!BU7jtHF_w552~sSwh=2!j%D*qh2=HtAg6LZRvAB4-t~O9xBkqcYzPEK?*R;)FM(k7 zew}>-R{kZsc?a3@_Ez-1&D7Ri+2A6LcQ=&MVEJ%;#rh+T9ggs}bJ(QNx(2n>(Dj=~ zCY8;7a*8``mDDRvT=XfAZM1?w>*% zA!9wsV9++MCzDMURAm=$(RmyCMPP&Y&Wt>y>_J*Vt9e78et>5Qxp8tOU4~^jz4lki zYKttxy#^#;N5MaT#;)jO3aGZSanP5kHvItfgs8E7S{X2T#3Xi>PSf?*+@&?@M|a6G zBP07v+sj5Xz$9enp6)mt!SI_ZvAc%Qd(@dkX)JBgs*{HE%b%>9=kx~LCQ2n;Da$%k zH%F2QB(6<6K)}e@?~B8KvQqMAY0uWqILj_T(|lTqsL5u@G>!ei1Tm9*u2H40jB}UR zcy?bxi(BA*&l9W?OiuXnBGOO{$wR_Z&`M;4Ok2X_(+N$4SmMG12dNdgXNA6}rL&s6 zOjwZh!83ni6gpkjfOo=ubsDi`dFQATFH`d9TA;% zBkJNyG0Wk(wzm5VTEK`Mu|e}?#|Vet-tM?JC92*dZn$yBdN}~dSu}L^Qg`;u=uUHX zG1cb;{7x%9z9pz*?@>8_$^)qpcQASRC==Fb$kJk%ZB$j#7*Wx$YsIcG-nc>zO_N82ee6PT9s# zxrV!h?shl|&Bm1rn*tvHWB^l=hti-Jepto=X>8k4W?IZy>S*jizqM%h~6DFtzzj)Im<`Bci&uN@ZJ7K^*qOSLh_#(3ix{0{}ib^j_Wg5kB%D2JARY_EM3qOQYYB9h%C`E z*+pk*@N{U)2$Bu%SchARa@-u_MvtE(Vw1A>x2$ebiI~3+e?$xOWJmo3$p!Sb)3zcz zOdKd=;XM2Rbe94wCe8rEsMqnfa!a{4oAI;6@uTf6I(A)Dlbv;W+`~x=T6@c~1R-?n z`EN2m5o@MtIAz%1k*1|CrW_Oztf9dQ)^$6QX@883?HQDZXO;~;K*zZCw|Z2^!?(j0 z;c;YYdSfFNT|oiTk(?S+L!P2SK2~b^gZ7*R@EImf=bJZ~KNbJmLYL?Fx=w+iTO-CP zs>2{r8paZzg|iyC&kWsfC1xYr6M7oE*D8es?eeT)Fw9 zZZ44$`dyMfmHqX<6B3+Wp<+EDz;snBUu;qK)+j{EaM}-ic!pqm+&cpA@#dS;(s2go z9!wS#Why`9Sf>cTx+mcJPVoQE{e?*>QjG;JU9^$D@;KJ|@JaFG(weK*LR}N^nB;#j zGq4VV1s>;$*jH-+@Y6UpK#{6SV2JpuID>;qul9_ z*8=mvWl0vn$|^TQI{DiblCxZHGT$SZ5`fiYV+Yz>dP}~ByR^Yp?>jREjHUH=8$oA& zRmj7)#u8N%gT$)OZ_QWMberwS?!{N()L%C5IX1OXJGNk~iEoReZqi2P!0X2QbDpRG zdnT<)B>d19MbzCSPa)7opwotr`6+?dZRU_@l#+$ep|^a(QG6cH9sy>?ARtlAAo(hL z4PC zKPk9RBZZ@Yu6~1y?&firlNI^<2X>}cSjleYayBer{{D~s9wsPfyz|4e!&rcWL^cgC zwEhUasxONR01tIgJ9U~sz%rY&j6)6ujF`A!yKaBSrtA;X9d&THyX>lpubw<}_1hiv zu}iGsxx*J8^J^xEkXoiHRP2kT8XngSLniMsd=$Ao7VhzB+G>{WFR3o4W=j#f&p5;w zZvqn!BI{0IUc1FxtB94y@>ph(5j%A4xiD*sXMB^KJ@<8(DCg&u(^3R6ZLM#2#OzB2 zMwM#5Y>?BeUQDaoIE4>?;Ih4#Z2ViGPkV)xW!QJzkAMv&#t9+U=cofvE%kZ#m1=vy zZSoKJu@%w5&92G6B{#$%V^Fy`X45Gq~3s?^rc53Lh>RtZlkODNgOT<$v#pO)=)i>FJK|-+Kdc7-`o>q)BNkTI81Do$t zWad1L(FZ|9D@Y9Ks#y(Qo%vaRW$_oW{=V-FR%8`OsaRB;h@&HfSYLdsG=ACtmJhe{ z19Uw+Uk^_uA_55&Kpty9{2INSuxtMelKlN~@poez!Ueke8?w0`Yoh(T9eLl(7QO!%_Keh+`*mYnCJes?UuRJ88W^kGXpaEz764=G38-*x8cS!6@S8n zRXOh4r;G1TRysS zNB7?UYjqUkz4(21jE8$AZy-7#Kq)p-Bmg#pjopNhYwul$^JT*@5 zs?T@$7TGb6pwae}!wbjvl<)$7ez`Cqos%=Trh zTTaORzUIsQv+(+MRZ!hHXt4a8Tue1Xh_~p>q{P$Jb>rW3Ar(J8|+F*;=48ze`N}oTO1xHNF z4M}O>lr9Jx8&xzR=`YsUAHcbr?5P=|*b@?yjzqM*{jjd76+C`+;TgRz$Nz&N?^^{+ zSvLMNTep*b>jLg&4pq|WbJyZ&v#B@&$4&6YNAF!-w;~g7VID4&82 z6cH3-qik&2Xi?dPnDqne(4{fhUA+bOy;aOkG;S++bg`H{;QL={8Rbl1ZlVmL#1V8- zbj|q{?gJ1inYCfwvmM}(1%K!EpL@>7WSOVkp{FW2JcWFsKU#YdxHr%u0~$$r!V#s( z3+?%|UHYXm+hoi4zHJKjxVwp*uWF0Keh~z)hr7nEvH<8liZhrvSr;GtsEF!oO9clB zRO!0_3XjTF1~xrZ44%7&c09sBkIRSPraF)0)0t$w5RK1xW%6YxZ1v5Xt;)!8?8E(Q zco~mP<J^mAjq;BIxb`kk-#<#ODrFeT#qEB;shd?-+3M4$ zUu{)E*$|!b7B2s zc|%c%T(1ZDgw4FS_ukCnA}wx+Kg8&XL>r0P!Y&?(O@co%&pfBJ4*$I{J{mPrC!?G; zsjfO?*=#vEzySW8J3KPD(kt9 zppsVOBa>2N;hcT0!ek9-I{QE&g&xER-oj=+YFAxJ0gq1xF`oouVK~?Tl*7hzk@CIVb_mg$I(=VF?f{zQk^kf7h>uveX-+P!3NvAqp8>&qV@^s z+t?iK(sqDDCYoS$C6Fr{=7}X-&<5C+@b70GiUIY_0Oeu+j$Dl~o#~rX&|I{LTX&7n%cBM)!6Sr3)tLvoKT=(yG zm42kTx5`<-2@g=JRmij5CAN1^7xDHxni~cjKAtEyctNv1E$Y~H7cC{n$|v9ERaamu zxArl~s|8xDo!<$0-#ifM@^C|q)bACVPKZmeAD@kAP+OGXUZVH8)o*^ z%}>s_QWItdKhB7#F{oq{c@eL$(u#8UBk?XvPcBMPRBTUq5ESlsS&uhq3bLL-yXqfm4AFE}#C6&SLMVJYZSXeBcOiF))Dm`cB0K@Q+7My&H zKJRv0xk|vYzc|=hfBFOos;8=bWZ65xFy+NuoqUmA_K#sMv+1Xp@qw3iG2Q zC$d1}ZnA&#J=4cRZutLPz2#ri|NH(gA?1)1HbyrxVjIms=^CvFf(YB_4v~II4;Y;z zrA4WMlz_s3F*=1Ih%_RogrX?={_?x_@%IlruN=?we4Mv4?gv&$Zk(p2IH$zhk;rRM zwY{p7Z?Q$_D63ft5;P(4EB~dC z8U%gsskiriHZtt-5#LuFORbEgEiugttW$0yy^*p%wI)7hbtB7<`2 z`o^?if1@imOt~~pHm^y_85PD=-gxCuW}YQc6a8^~_gpUh{NVl0<2OEDz%-wRn=<&8 z@y2;4e1XGrqrUq|^YI)lh2kiu`-(Re(?@o^shE=qhHpQe`V|y>dKY2pW$Ik@lB(x4^{MrMaGMIG@Zam)xDaqkI6u%TA;rvJ=TeEJFXQZ_2L!9ax z8?Qe;x3TxwIrOpR;w;^$RqJ?ZmHRH&xYUeU4a)#wd?OTHhVzFvU=b5TS+WpF%Ot5J zgQ1u>!k#}E20QjhbNb(vO!^vG8x~^>#}58aj?y&-Gjcq^%iu#IiZp6sZsD;mma zS%>Zhf{32~R6-9X^!x#jZT?6^zAxpGJJmk->P_TY#w*QjvDx1S#r9SqmK zd6M>@_7lhc@1A9d_QF@GsBZf&J?uMjV9js)UT6M&9el*@I~?Lc%_Ut9*IL-S04{+^ zW-_gfy?H0|d1nvrI)0aVT=lyrOzY(RBj1{PeDSfn_Sa{TpK^PfIw-lH)?l#E+1~!e zr+I|JDbB#f1H@Ojh)=_QG-mc2^hT+9s z*CRTa?fwM7oyV}d_UU~$i_Jk1sbi1I2&dZH1O%RM0#=(s+=8u zuKwf}WJs`$|2peP@7Jc^3OT~%Wt5L{S!0|Ik=Yl9%qE!^wZ+c+l=LTmEqTfu%CynO zSeenkX?!BL#75KWw(G`H*b#qXn(*!jNylUvhDJSN1)!AiPrT8M8n zt~?1>dNa|O`}R!{+Y&o(k+Q!hBA{c3CH7^2Cut>Iu6@`jOia~<<7pj5Z zf{`t^T$vj-zsUUW%G*+^ju4y0RdrGF=YTq|T3@lv5q#b~n}TF9ZKr{d#}raGk|Xn#ybUK;Z>3D%r|9-xhox)6~Cm zpQ&qB%2fN?x!M2z(-PJl4`p}B9Aa7zZP8)Ka=s;}yklHun}Z8Oyf{j-Y&TF3+*3Kw zM|(9&TPym1h*0v{h#$%fe~Y<9VZCdrKHg$?oE|~GGt#Ddkc;_#5bYCIRHtP@?>S|% z9&NIaM_}DH%-;%)h^ zl#*}9qR+p#%r?6#13QmK7)H6)J6HeSVxLD^nk$x;<%ivrb z!`-BL=aOu0e+9{2>XwV>xS>_e6n+3S%l`RTg5{PbxFMbc@r2U$G)BWKdq)2niur`N zX~(oAWCx??#dU4^XFFkm93!mR;$&Ok$F0Pd?}-m2)XzSwJ-E?zwzjrrA4=+(%ly(K z*m9G?Qwl9e!DuQJ2xWxNySu)ctld(oefz`fy%6dZdJL4`H@9sK2 z2Wmu$1tv`M?$u5CK4`L-+WM$5&EETGalqkef`~>kH`w9+-G{<+_ov)4kFwWOwu5X^ zL9Nrw%)BuMgmCMk14H)*elK3uX1#3}627_o{;aVS3(0JunDG?THR{);3z|?-xS^2H zoHKSdqty_;i1eL!f~v+Gg2A z`H!;2Hp2bpL0$K$?4${_H7(KH1O- z5hrfG0#D^(Fm5!w`vPr8yMVS++S$I#2_9|$OVlVIPHIhui*mpEfd4t38Eo^iPD2Ko z6FbC9Srp@MCz116|Cafq z<>z2kqyHvO(^b{Z0`0t0TPoojH?Ee*yA-@Hm1z()NMCtPvfD|${yR~nCr9P=w!^rg zySr`j|4pM}!E%}N3H?hI>?k3*%jWrtTU`hFS<5NmrAiLJuAr}&Kk|gbF-xr0E@E{{ zYnqh6if29q3rH@8{!R^~8du=W70S;fd_mh0ISX2gUbG;4FV36^Ifpx3Qq(gVqb;y2i{=Z`1=hd4>6{=iKU07pIzAkfmh0X+dgzY)baIt|L)vFk?_l{#`RQ! z?o%rNpl^;@itn_mhOFdQ#?nH%EIa>ww*?eTZ23%fwn!+IjeLXLxt6j2CyTyRRiH?L z>v@dFa{j7wy=-Uuucc;X&bfqLJ>a0=O&U{5FViiC8^`P!lt$%o73N#d-@RVLD(DX= zJP4Mi!@uy94c;r&YI?Si;?(um+rDj`;Va))g8bsEOXk6RJm#aPt(AS?Fi#H8X=g`N z=hz?m2UG7g!Uzv{qv1>N7lb*WjzUt#2|>zFUe2>u;}V?k)S!}s`6=xf#x~dp zvzc*0D(E+pR;SLuBRDfY$66(<3=px)zft`8x74$;u#|ra8hglWJVx*13~v$^nEdP-{gI|KA>rMEAxS4e;cuJpcwirbZmOr ze2bkkL^n?KZYJ6_H#g$ZnLzZTn@b47U}RX;P2EwvN?@3m>65586~F(hHrbG@t2B7Y zRmA#v&c(Ikd_PWyiI2ChOb=Bjhw&cFD$EjA40%CU(-b@vI~z`lyIq-<20A$V@KTSN z@MCRBLT^qjIuVrZQh85nrP%<=V73#n{J82-lv`7(@4@?&nfx9 zF?oBYW&>TC`TZvN7?fGypC=^q+?;rSA~yVebxT&8#-)|ZLbly41^*lJ@w-TA34WE_TlO#3AFQL8?$y# zlUQ7z7^%v53_Ks;sWUjzSCl7}bv*ZfqtC>hy}6AY`IX04lzUbcK)5#NVp1zTZIHLU zB3R_8*UL@!AeCy_1$9>MrpD_nEHcb0r%`eJC7io~!(b$w;e(NSv4tDH0PBAkZg%IZ z$Vk2+YuI0d$>mHVzUu-AYb((w2wUecbP^592o;C2?QNct6HyXzljA~NUZF{>+vZ?P zMDFvTFjhU+Ke+Bctm<2Cdja~uJo88frNX4>WD&#ub%i&R>dd5iw#n9zk?zA2$vd#c z63-_-_SRv+a<_e8?J`#f9TIANe^^;`jM#p8bv;?=%^C3MJ$S+1oYYYB>ANe#K<#3i z2x79jKisMQ>y_qQ3b!hAK}X?P6VS)a#y#3&uT=5b_g@14fPQ?cblAHYKJ4in$I z4HesIq}(O@;3eN(c;us|DKevKOdQYa6@~v@ft-d^&R<+k!#~t}F^qQmv~3%jo~t>C zW026&K&Wc$pu(E$Ilo82R`S%nXD>GNST8$L2S-t**>Fk!uYqSA80IOiQQP)_uf{@R zOHRc9RvF%a@&m?!{^Aop_0}yhhqaqqd&v#G9_MVEKg+(ePN`3&^C|xP+i>6c2jTxJ zXe8D~NyHlYisGq9*d>ao2RSVXqAp>q!GXT(XHW+cU5JmDxJj=%&Tw-%w`FoDGDygz!=gjs6VjY9d^j~`3vFcp&~Kl5;D z*K+$Yx_gJE?YWH6LS?wr;u&$6oWSj$NB4Vn+`~#j# zCr^0V5A7A4Gt4|`S5&obxU*C0_dGMpbzt*~B=*TjHTGG54g!yOa;Gvg((pI`csJ^z%A(ys^K|!l{j8$R(JFK46o&PZj5qL<@czX*L(x=V}TK&80@(-jV+=YIZwwvpd_B*+)3 zW2=`JNH=?MC2855vdG$%DX$qPH+7-oZO!dk!Shs>>BrL|!$j+bOF&Fk#Uvq%mlpXS z+~dUDsR|H+oD+8DI+L~B91r0V9d&|4n`dfA3Z>hzkkf_r*|U=AlgdaS=~+SoVv#>ji1j+W8eX26s1_&~CN6P{t{Kq#j7_vZ#n?!d z>V&BE)j6^7qnqK&{Qzdg4Un}4?LI+JEWck}EL-_=u>BD77dy>K8k@^rpC?VWe~8x? zAI;uhR5R>F@4*}I8W{j=RC>c)((^8V;wLtTjZNYK;x?0UA)Ss&{NvH(jUR~@4R3G8 zn;8uo&@?72ze-tps%jP^&gXsiYoyQMBH!}TALdpFDF|@2625xeB}g3hs8@=}V)`uH zC7U(nFgpF~ull)hfg8o`;McrNdl!A$?0w%P5aoL~AEIpaV{+b10pH1E`=Be0<1;H? zR$4+7N>wLn)Vkc1?DnAbgT57_IPhjz@Z$UT_W1;w4oS|QO3eq%G zV}52$8apX?gl!!(v}$cEXP(jv=m_?1$$u!=Yg%7q!Az-!|D&CrPfc4I_u|28zJX-T z(F9@RjO}uv+vD^f67N(4FvLQ{ zmUp0j?tOlO-hZnCXN{i|K0Z3cDl&9tA2L%nwWA2HR|Be?O<)nMKi&A@_^@vKK@H#Mn4CEb|t@;M7 z1J1m58t>7xWPEADLQyZgy3*Vt;q(q(rFz!ao`1iqvb=MLMM4n8OZjb4Sj@k)8lk-d z6J_r#O?AQ;8h=+Sf|O!$PI=Gs?x?IQ`k(j?M>Q_e=C#XkOh0;%H_P29^YppCZ$}dK zTP?c|mKMA2FA*WH_7=mL-v@OlZUWTRTFc=-8VcuIEZgxnZ(`nlq7D#7#!%s65 zq zIt)zpj*ee6KIaG&*G)@mYCT_lk```1rErsGh+&;{eJ}3PKuD6yEj?6_j=eX1V$L#Y zi*J;26?Y$~!vtZ|LctB#?@FhSa zeUY_FV%sIBtWPSYaknHO(REvyKCt9MW&i({oMP_&LLS#OD_Ryh9Ux{vBcI=r@Jowo zZZez8F3L>ic3i4TzTmEqzA60LDtPQc!Ym4%2r*DBo_D5s#nHHR{Y@&6RbAeM3nchH zhnl-9EyKO7SE-7Bb13Ra@a;#yNLjkW%p0A_*<~u z!lu>}6SNPD;#*pXlVZVF<=DUIxb~vceEZ4ND-~JecTgR7a4(a5@E+C7W6Y?Kpy2Z*aPZgIFCk$g5?%3yl`|$hbPM^A4+mE+?HlF?PsK$9B=5{iB z;>0Tzb$(nElQ2sDZon%Ihj=9Aohjm8cSJ5;%+yeTUIIl6QtEfq9n{~OQ1l?E&{f^z z5SUw}*^8a?T%hQb~dR%u?`JS13^JAo=uUySxk|U5-SE*Gxs4uI5y8V0I z!vC&R^q3dCwm-hg;c3@iAa~OAVlnc3tYrEb3fYR1ccdF5ftU+YZ4oaFWKX^?Tk7ea zxLS-1r|*;;g(iw#2Q%XRw0O5#Cy_vzk;?QCU*xbCLOhcQPsTPHmLC8b`o2#KYiRma zIDvmyrv6dJ*5ug-^u4cY}dq{G+NJ9z1wHj_IyuEwLiEW8X6yVF+0*RnoIWUU8E&Pf_ zpS^|M0zx`x9bZrlJ%oqVI{qxLRaMSYMHi^1YPUcXL#I&q|^zP$KKh-Sw_UPpoC6Sk^8FpE=G&ejCU z7h+ZI9FwhmH}<1iJWMCE@TM2*u|4ZVY!H8hR5xQD+m^+NC{L*{@j*q#_7x*|dPd1O z%*!7;gy|_8L-CgIO596~($M(M=@pB;6_ zrP?s_D!LRV!cOI2y0Qkr>xGw-%Q#CTbB?G#(A+2-*?=D=CF+X@z56I-u)~ZCf3IMu z(#C9i-SCSO)<>`j-t zWK3+9+|?VqXh zOAGp5T?;-0RDJs5eu>T1uJZVzv$1A4KjYjM(vf^!LHAxVo8{Fu=%In`==n)8 zfmDgcw{&#Xh|7<)#}gu5I;*_NT-G{-%)>fia)2`Pxn}29!276)szHyvhgmt6BL6Na z8Rn7N%B)MIsUhbLVWI$QeBlo%)}+)BbUY@lsdb~xs*jyVwPZL)Hpw_gCX%mU+)k{ zUxj;sXAQbC$^se)3}0yVjMg47(y(jJ_v%&MfK4Svr-Sb7sEI%B4 zVz%P}4Jet_g(5-Ma69+tr@pL&Qw%0|7bN(Qsn0NyIM0(BH{Hg zWA5}NYOmM#`-5v!h~N5)MIw2jZ6z=Bn?Tz}ZW-DQFAsH(*>#@JOcuC%+sNm8$Fb3~ z6d<|acKTD?N5J4nFK_R)R zQ?xgKt23j~Irl$?XCB{{x}~xy0(=dDKC!yOJ!+ivyXRL&ZHM^NjFQ-;;qVOMVCeZj zL6v0>jt}BjY$Ysb#dtfDQq>}D#SDi*Nv)G4kbFd7O*aU;1N9tK5oBZ;9wBoW8F4{+ z3+dcaLPNW)Q3*MiF>v*`nxF#!hO#T5t!G6U`$<)`=H#dh<3g)z{Z-;q#+IFFEOEY} zp=~u(&Ba~qHs$_g=^Xu(L`X8QY=_e-*g7^EACb^^S7~ZN?Eu{`+ z#yXUjgdj4Jvxe?i%{OAROnS+CkcXP&rDR|*C6HLR!G4MFyHx_6L-3q)x5O}y!W>*` zPs$GOiM2=}gO+wTK|~*IH-J#6H_pi~Gb^7Bl#1J&q#v{P?&K>E8XYM`K{`>_kFpR| z;ZJpPzi2vrd**zCFK<+;0|xu=vy13YDjwns^@GH6-OpbwxCs;#9)C3<$)y{({3BJ0 z_fxa>n*w;^*d5nGC=juq!KmaO&3rrlen=>0O9VYtMyY3!Le^W=EP0)#nPyxQCKwcz zIyh&}SL;67WEZq^qlsDnX>}Az&{_wm%r{2R&-sKQbPkD`Q%cmhmT?!x@myKjiuQVy zal*P9;@+q(|DE}&;g=ZP?Jm5u|wxEDW^ZG~pt0Z)}T$J;_aK1}is z)K552V#sqrzffoq9wbz$|m%mqT%9&*r8Ys3}S`^L#t+> zNYNW#R9p|BU{?ssowbvfMjyXKPLIAfN;@SFP!8% zo))zUH=un)H0FM-yuDcsPua?wSu}#U$x0A}khv=XrG?Yk0cpu>4dDv2&j#A0(b;U+ zinVWA>@sdZy~2K5ACeRd5~ORJ#IAsaOn~D@98Ss6e36K_4Wcb$a;oU`%WQbwQm|j+ zabL(6${V2TY}6~tWlyOCiuV}>i1*yDpRXsHyl*^}{#MkZ4{CZi3ZQ z%~g5Lbhk+PUjV;8eIJSRS{0G(GWn0<8G%OC|J4o*em1lHb0`_2_h>br|K$ok{7kbC z5YfDgKi0use29FkD8LT7?XkD*Bn!av4=0Gb%50^+CZ-?EIUbJ!iAMy<{$=5RgtC%r zO&m_bC39$)>g9iPC>f~C(wK6uupv)!*TPs^ zK#sKRadx{k^1N3XXimj*sWrce%Jo`_mz?pGIkA`HLop+2ADS7GJXE&TX6F1zjK#5{ zwol){DaXfonhf>XHGNkiH~+FcVhLgcnNGx=w`xDaKu*{lCRYnR1(nTK<$501zVeIq zMko4kt+4gz)s90XE#RW2IgZZ{o-c-^-fK6uVE9brnxDh+i(Zd2A6r7%7PhD`!Wkl!F^zn(#e?#Q3fF2c4k zc48#zIMIG`A~K2$K|U%WBQycYKT}<%g;9DRv#UwN-{bxGhP%45oE+vj>N@0o*)=9B zrrbciYX$05vqiZ&;_JFXLLFPAK|M}r=8}~uec4;t!yRiy2mUMn^q-`ZN2e8N zo$ZcE+qqJ)7Cv0IRog>Xgyla|@V1>hES!5~a9j@&?*2wurmRvU_$Tlql!~VHQ zB2@9`(Q%j}I{3Oznw2r>sxmL{1j&DglmIQ<&tK?{`Oqiy2%P+?x-izHSIMq>X5${e z;6Q_Y33(%%af`1tVRwB&-U(GNHV$aalDG+OrGKGHx%>QoSMmq#v|{BQb^W4fW>?n! zcLm+?@Qf{Pgh2@+DTv;-ozA>LH`}fxt#*=DTAkpVE}C@@=*7^$(Z&w42MY%$SLgZJ zy~P)8i<>zrnZ}G-lW(Ppc-}EyJ@~pGvNiL#b_nTiZ@{QOCg?r(YsjILBR5tFNVCl^EEx&Pp}0XC3)weZ z(dwV}gCF-h%ILeta7v__Gx zVeZ#NTJB4y^G+`7$?&a0x5NJ~YiS^b8%DO3A>eLZn>>Z_r*ea(0)%gsh)eVyq;mw` z%EZ_r*vhm6#&|+pEu#YR%Y5P4j%kc@FefcRw2<=#$1OpB3O=Wly*-8twf)7mwQkyS zIWUN@a&kF(aotLt?tmF7RfwsDSP1Q|>OT;^aBm1pJvsH`t<6s7r)e@c{->xYp=h}p z{@~i$;VXt_S>Rn%EF!5VOfz_&%%wm8HLAGBDWNwRbwaNu$rooz)}gYqC?J3nWa(2| zNTQ1doLpm(b8wrpBc};atl%Qz&^7Fz_iZ*~pl_LqjRv;gL*h}zx zJ@5wEmpW{lQUIQ70D|M#`Q*v>jJ0CKS-YO~ z5~xMBU3IJ*hq8};dduHVMY@#Zx7W;C2EQuuAn<<&Q!d#^gaQfi_mj_B9+s`%gQk2) zH}S|j=!WC!=K_feK%J9P5eX~VBTKVNmp-6WNznANs{C$%t>aE{>$WQPcuw>-?w{An z%)V7QXGV8tH_Qymi6-bwhs$BNAc!?bIVYq1@tk)t62LF7zG0sxnmyV(J&AkP`Pe8G;IA<5j3E6RE^CIa?IuuVG-^j0qdw1c? z+;OufwKO6g$+j$zwz%Q+6x7^jAC3(91*m_Ew5YBh+mdu8IsCAs4+~8ms=O^E3_aPT zW^^9$E>@2E7X4#+#Vyho#j|DlX}PnnDfs%EMoLK3m#gA3MHHJ5`7IkSc@T~VaJri& zH4FzeF@6_VmYaFJra8JRaig z455$5?EgGmF2RB(0zAx#5H@veYsS4(@5p(TrPVfo@9ndoJm(@F5FP@#&%W?RnC!Le zvnw@NXpnx+wdp3nwvI8+KBqf4b@{yoL}*6F8{N0jzq?wMPWr2n7Q^@ zWd54wH@5i)4Fl2%(T|D(q^Lbx$l>!ARcOg`E|^Pqcg9dEAzo#@@(kEcs!RV?Vyn_u z9{-14Wr)sEfMsImrBrtWz0a2~$(Ov~BM+)Nc1lFU_mHCH7s9BWU>TDdEq@=s6|spz zV-wxDx57mPpl2>%$sy|L@Auyd9z;g`^gB(u7hn4+e8bDtcd9Q~=IDid1#=?B)V?Cv zwQfFgW18nxxkHw>>^%Pf^>Q}cA%O`Q6K|GQLzMJ1{5b7W{#rTRTAaYQO4F_;D<%)# z;N5gnhoCdkaN&ZF*5SPnZNDTHeTPcuF6rcCm_9%>|eY^BV~8 z#9Zm7!~uQU=Beei1{!u(wvC69nS`u#;%$wTAUZn|y*FibeP%pCZZu@oNl#rYl3x_Y z>BgJ+kS*X{o~D9${2pGXg|1I5Wlgl2OI+=x<3{eILugmm77#zyM%xf`>cb|*CQ2Ts zubvVn*9w}-^7JTFD6eGP4;ZJL>f-71`3d-HK~4_Q8&&kjJ11_JGY}5zO(?c< zyX~qIiUyWmVo7lEf04?P>84O7=}^*9E~R2c{6ezXv~aI%IH4fTxaG;q(6lmuQD5PFR^8eN-KRi-X=C&xj9WQT^KV3*iw4eeYb3(fsf_tpJn9 zH|y+}Qo|m8J(R#6FnZ3MP72fuM**}?=-Xu-!Y?`>h*w5HpL*{pt>15UC`70R`DK9B zoNNx=V9hbX*b(H*35(&{1k)|iKbd-}Z!lA0w-6erPJZt;c61DP97j!DywKalm$XYOS3yBD)CCN2u>e9Xzvb}tNx|)h=)})$}=1Ac|=X=RpUFQ z5TY9RzWXoU;+l8X))}KoygL)yd?0H@!siyxm_shBt6$Z%4_F?2Dt*vcPo+Qet)uYm zxA41MFM#!xt+ga3WezR_uZ`_#A;cqFRJd7Spz~_dhTQPs<^+Q+v-9p4-aEo$b1nH> zj?VDy5}V*>!h7s-52xk~4Lz`p3^rBdv&FrWbj>IOH~VDBk+|0r=w=r zkUl5|7+0D(zl*+C!`75mdT4i*ms4;g3wQXSrwx*HX7;(Gzgd3E((*+|KZWaq)cwWM zWcmkCce&yO$Rd3rHT4yPcyT>C);o5xOwD(1^6XiCdd`Od5+(*2nY`k6;NlN6b;e&J zx#*-K*pO(Q=9K8*#pN@(ZiO$jV%Or4ITk{?PW2h|?KmrrjiEFSRXGhN#oU>qZzwvE zjNGFbO;%CL9@9hy)v~2fw|qmE@GjZq8SXq$4>I-j!{iBgs ztB^8hvVsPVht<_SRQ?_)OXpRMcHa8gp{8!i?=E@UnK0xM84sIK4X8|XyA_aWRFOJ# z@qsR@b%H_E!V0#k%<8rM@EYi(6{>JMln%`QaDZlXJgp2?D2S9_k?N!*#8ZV$lc71c zPa!H8LrPvtpB;;5%hJ;VSHBn$v@kmQMwyE99KpbVmmkr_^6N|$m*zR)==)m^3VoOg z7COeZ-I#_KwFEz`liq+U=i6L!9DKb?m6Y42Z}>)`LTbAqgczqk+M-=e+vaWZ9h=%B zwQ#c+LY$MTph;+4*uNXHgOSHTM2*$uCO|xfnHy!lNLSs$06OAKW8r6T9GY>oe01qNg zoXhWIh+HPay@MfvB>E8-qv_#zuDU%QKp49%S`Pk?Hln`6vadss3~e>HQ>ElLPoXDu zKlLRe%VLytg$_Zmg=r_FLD~;^ve&3(*@Uj!!`u}!bskF<$s7xCF_zMZao*=2dZISu z3WtdqC(wzU8}!pypJbbMSuPx|p9_qvMdm_hQ*7yBiYv|SnJ2ZXyfCONrqaCzF2^A5| zv7ET&=Rlw}m_U!NaWk0Vz{}6a zPz)Wyba9BmD%~wv36=ah>C zGu>m@gsWCvrD!~{m43=WjKc#0^n}BhI6Z_)aF@9sVzUXy3gd_dYABG^P>pb zt+HW77hGhJ0I+&4YJCOsWC35H?r||JtZ`H|ZpjRk?10lQvbG%Ww{qzNB zS^FRkChLm{ta&jw$}GU}AEB+JMbAu{LVxe|KO8{+aYly>%ZY7JacL4tUy1L`JD6U?G z&eyNCJcAm%HX?MB(~oDgVjdD?n@%P#il{(wl7REAxh*1gHV482x~6c^kkf1=cfe*-vBkRj=Vs$fXck!0dPMX6v$|n>qKd;m#15t6{Jccjd&u`0?o81;ALJfVh5- zl7f+)lbOYFy6K6u*%;|sz~+?ru4?ZPqAYz;M*km4L>qTqbyJS~AlZ7o7xWhyT+*ik zV3kw`1Wm%IyfDB)pzI=X>pZt>pQ5VDPXnt)>Qs(~{lLfGKFr^wcdtJ4$B|g}Zt{jT z>bmT6*rpipifgkPuRLg`I1i948CuPWY>Y4Lo>3Vv-8@cx5{^A2yWQAtHq4eK?7!gr zKx1teT%1+?awX7JUjF;^6|_G5OVC5U_^+<~lEMV$W^k6P7SnVpQ={a}G5hG{4HRxc z#a9_TQp4P=W~F-=q>j}(+6eu9!dQ4B5r>}4{1&@RXPy#^+%8-n>f05oTyg>VO7p8B z7btgUyRRS3f}EdkOQ`9_9nqo=yfMFN3X81ns2EASPhSjZ6~b|?k~rla6y#V5JRVp^ zrdur|uG)kVVno8kKAPr`bw)sZ60>b?3crtg$JE9|WFy4UTEN^bv;4wwwsp0iWNXmS z3j!spB-Do-mLWf_%A%Z+Eqdv9WMdX8D~cb37+PVq^(h=B)7A}xsacF!@f%W!yT~Xs z7mYQ8pb`R6)b>tbt@$d(1_0ejW4VNMiVJ5Puf+ zod9tY`X@TG0jEc4tutz=Jdw78B2&j5+ZavfQM6zoIZ(mM@Yg~ZP+5N8C@sGEcCiq4 zXmBt~1wu?{S zKkhIolsSgs%#F>7w7|c)LO8=Yq>%h-o=|OH8V`iq%_v0j$HVk@C`7UeEMAB)5G}kp z7Q|Slcib(zeMBBENjaFwz4$|-N#OH@Tga5_Ch-5%p+41282UoZYZf80t-u-iS4mBqx>L+B68ax;E z;}*{)FhV~F(dVaf6qs37RzVydl{@EA0=X17Z!!KmqP3yf0b|$ro%aDTLmFReH*D-q z?sOpw!~~?Ws-^`}2__uFU0d|yV=UP&>)gbz`tY<%E3Y;XiXjmf!NYop%551;U(?;| zrplH}J-bbyZ0#&Y`RvhhgnD=R8yVz#UHP({ICrOBhM64y)qi~GETH!Fjm<0)Al+h0 zM|gwDs8WRV>fBjz1r)Pvj0x7quokROJj8CF`$0>z^jPaP`-{;klc<)Vxw1h#wid@x z`cdoH30W$Ov4|cYbNH%zTNxuesdlwY#-&%tsOVdUZ35qD&?yV=DSAR}@Uu2i9WFkU zCTz(saXAtVt z_gE;)bt^WZ$HuiWv8Q+jvlp&DiC1|!)9!m@BS`CEYSZM*mFFtb401z zVc=2?g!nLVj1~unu-|pJ4}jNd*L`$ybrw$s=^qTU39&xTmOzPR_y^iR{U0^B{M3{_ zdEi_J{TE7@ZBw~<>~oTwxac@k?hJ&JNrEHRu6pt3+E5**w(%i%_sUr(VFLnSqM(nA z351H8fboogG&yJDEBY0h7-M3-g(?~u2BeP{?GoYTKjEcJnx?6fYQm_N=U}mlu~$c8 zB1u$s{xRJkZEl5zn5=8*&Bh|1u*{oZ)7@)z`ij2Q&keri{2DMV`I!%)kxX5an;gIF zgUwRnwT+RNJk2JjKfheD$PBUux~UB+0eAa|{JJ~8WEJCB;jT#;qFHqVi&$F+fTA;^ zIjaIddfZ|}*`{ioEG`Se8gN2K^ha_ODj-Sy3Dl7TQ|xY|nTcb$^T5~Sa$`+m)?rfO zh8zi{VrDHo)GzNtwgh9cY@Ava`8zcyEbgLce6x?U8i6@H@P?7BPmj6yN-n=_EP42l zZwiUc6d}Yd8wwrjZ#G0q6`s?s@a6lUw*vWH!C~EEBwJ6gvHBd}l!B3&0Vz0-HRv?o zin~xMLuopdTxc@<2BjY;E7k_$!QhI}EDryqEio^l?a*x3{**w>!~27hX*<#kriD5w z`aon`rm)fX9MHPrd)7?!B9hln7 zkry>WGtykm&7$h26Vr2562Hka$=H=~6E?eCnUujc!&37d$)ltZ_@^II*TYx*P~*1h>7mN$sxC6* z!`yBOZRmjsHpr$$}t`N1|P}s4u;NT#mihlluN?7RN7oDm5 z|0p7jsO6n9VS8T|9&zJBl$0zY1x(3ZqpyAvCpj2bHf3r2EQc;Jis(8M z0n&Ce^0xnpnC!Lx*WR1Hv$=L*nyOuwTR+wdE>}~QFn^CV+SNfo_m(R8JUI%v71O0FV$umuso@li{4l%!`D`Uo zr>1O7{Xy82AZW}r2jz@&cu!(*RGnp?f={hF75mk_HPC-UJFI{*pAwOE#^h5QRt9DOe1eFtoU zfvP%kr==CEzMKb)Wj^2i2@p{9FfbrDPH3TbM|kw6@!=HRyarR6Q8&~)Rx$5epZN_S zUtaq07RzN>R)J5rC@t3su#c`UvJA;SI{3_t6cqM!mQ}ZE$nc*@byoLRnvAl#@aJ0RV|vX23pZPGhSOiO~0c3pFBoWvG(O!A>@!^#5B(pYi{k(!n8-l zhq8LJc|L%0K?f|%)T>6MEJ)iUYohc_{pqKK4pqMMv@lr#Rrgfx>Lap>vw#Gfii8o! zd&H`w35A62<;%0L*5Ko|G9Z+J4?EledYyjmzO^@{eKM^ccs)Kjn4uxp|Hp_(gNjzm z6u{A`tv22BYAcFy3U#%>Z~Rz=hkr9md*~plMed15+CtZ)?Q_Vl%dP7qFV)X4-7At( z3S_hYCe1&$4Ji8OMw?v?VI;`Y7z|XU)D)i%pmNo700k3vmI0~ak9I*z^O|c%bJEW? zdt_pdTHF&5-mY{X?}wpDJSq;w26x^J9Wo4JK4mhb?CNY)OMXu59>JfV71&Q%@Q?th zBG=iJHuxr|&<1>xew6tst3pHiUK?o+JE3+CBEj*N6(7fBGH|NtDBe;0GYpRL<0t)e4AG0P_Sz_-b1_dnniXZNZ+ zQ&iiT^w8fdhI;RU{bZnYOZ1ej;WqmDGSUeTKO)B{5etdUIG4Ix2*}DD{2s6u;aDJLzy5BFz{Dl~ znib`J$eq)Bk@8M#+bHPkGv_!1rD5@pgWmtfFo<-Xg<`#H+&&x-K<;BMZK8NrR*a}Y zxEp(r975MrT*+&+5eg;1f8inaVZXVkm1^NUMk3A+yWeJLrTf5^ha#`GUe4}ZU0Qgg z7vnP)%h()9xjIB0A&4CF6RQ^7g(SKatUn>$V+*<5RigYMro3K_3z+OV6jY2T9E;ca z{A^3wOWSq%277!}>v-{*qA+WdBrEZJJ3;A%TEbfDv)rm52^B*kvg|3*j2s20Y&HYS z-SqJs!~v>NaR9}>V!#F!p@mF6vyYZP`WgY*UC|jEQV;w7(@np7;bWvLzdn<8bpGK1 z5dWr4F^+><70@-%gEZq*hE1VC$w~XDE*!TQFRxh7(Q#FS0aKvO@>7g_s3-HQ^YE|w z8C0<#+taGz2~L(yf+HFV$5x&;E-MyO;%5oLckQn|QL0fCFYMuWR@S{mTranv?56C3 z67!-?cb~rX624Jk@%X7LYfU8D^dwwU9<%Hb}~xWmi;8Q$##XmQvr^jk-rDjakaD3qy&izbB@8 z?s#<~vf^886cY^AM&dkn&EQ!_s|Eq^wj)1<(?U1?q4wU1FU2 zi`8eaDxiMaRFOuUgm{}eGFP0jUP&QzF!KAFe+=AKHfV4WIxdyOu&Sk_uR=LJQ9n|V>s_d;=n|v-W@{eWLwO*k ztS!dk;9TW&EubF+O4TCWR?&Z{zqYUw)Pf=$i42V}cPMjZ)7 zo_ptem&?kwzfGOey6AvHZHmpx7Rp`m&+6vNcS&%zve=a}f>Y@1FI{4;h6foMB`Ron z&C}MXPjhvszb<3%di;UP(z{<)lUf1hE3w)HmX6w%N0cL;54Np%o+surkJl_Yqt%JN z#QPFmsvK6V8<@4OE*T7EKf<{?64W$ZG*z@o@vl@Oo?<2O5#37UkTwDHWb@F*E;U7r zlFyY}Clmj=22nTR?L7PM36s~3?va95mlht&QzyN)US+R=sv6|5)aMK6^@(D=*FrHQ zhAbR!UD3CMFOJreQSnJ{cAa99DYZxLGWY++Bt7w|uj3;@70jl4sg8UYxLd(7SSm(G z7T?$f$E!uSjX0Sex$02Zt6zGT-i|YpzY?Qy3aIyh(QlzcN*+EP93pJxo0(?CJ7FtJ zRaW>%){`qUF6v)dNSAMMtAgs#^m=9PhNeBjn>O%D0%fnSM&=jzdV z-bCUrETLNQ@;6?tLrLJcPVly)H5-w^17k4XpIA%EhtP-8kraZeHrYu49N=fw7$7_c3 zA)}6TMMP^4FF*2?4!a5cbzLpD#rmB?SUz7%byuYowb0w&{DjynEU>n=&8fwWAJ!I>{HldRA%li+Uz+>IZ=Zh1VE-P5qDBq4S zhymr6SnoKdbHiw8-uT3oa=3Ns+ZL>D#u?6nKHMw6zDJW&~|^v$?Elex?ulDfMlYfXR5(@Ro?y)-@ZX zM!HhQ+~vZ3W7AS{=m-yVYxZNmQVgjrDeGLv7mR3r zR5>GMrDK?#JGYRg_Tx11bjPxA;h+^fEmGfTyq=#5V7ly5RwSij2ZS(giV|7Q%q7sE z=zVJ+Rqzv)>XFo6l~(dEXrdD!2%Q6r+;+5Iix1sYQFw-RmaKo&P<<>N7LND7k4e1N z3tjzVIILye@Xmvk{7SnoDRniTbH%rs5DCDwdsS3?SxAmtMlwjNmIr+{yDkkk^1kyP zv7P!Du72Bc5sv%gU5dLo3Vru<_(;u|_QMvB+ShIM1()ZY=i;LoFvxep|sH{xldFW3kqRM7kCXB9cT|cezN# zxt-7|nD)rY?$uXHv8gLvQ7_tABPm~e>HrI9%X4h5sv@tD_Gxgdp>*Lzu4BifhEU#m zM_7ywolDU?sgw~^uVotM z?;OcI*E(5Z45aZp&qY5{ogA#MCjgG8A;JqjDKw@y=yj_4=Ogx`uY&pss+0_LM`t>; zS24nIEDYx1BQMwXsk7yWre`*fn0aGHr>%YmoJ^YpDL20CBt9lNY3R*j`nE7b)dpsX zj0KfoR;H6yUN3QA$I(c>_8a>M*E+w0$zSd)e`>#3^H@H7yoRk3jhdGKr=liC>Zi@& z5q;K}{tK1TF^MWymGaYxc3lW#$VRWKh@?E2RF;V|br!UYRy24a{>71`ciP_PdpB*J z*uN#)#jV+1;XtBY^KVCKTl*vCF#X)~s%F|w@NqfqV9-c$j!{RxmH4I-vt74q^U=X} z8SO@u-P!Lg&#jolEgBTz0=cO9_+S3mkHmRho2kgq(C4ONS1YJe|0z|rznF7AsU~A0 zUXjASu<{O8UCiOAWJ#$+TP+t1a^w(V7y`Lg-G6dW%6I3)-v_EG$em6VbynG8p+?V) zK=!JQN=!#B8MXUHBl6h^ipac$Y1isPiC+UXb`}S=4w`O_;$Hr|7NWhzfzIns{?J+k zrm!Phb6D{{XDmGd|FX^L`C$!~yN8|>t`ZOp4c9IIq@z}9%@D##%U2ht}?dt|J zEDDj8GTEyFH0*KRck3a?w;Z`eyUGCSUqrD+GDLxVmVMVp%}E;bRaBp6RQO8wZDD=7 z?t1CLh$aJ=(O}Xe--@A20bF1a$SRX(oWh?*F}q%#VJ&z_DO>D7hA9SY;vuH9MhSVS z2y(&FTfn9HZ7F%fjb939gk56~W!)g2QYg%;3*XES4H{|YhHTkm1xmU!E;RqVu2_PJ z;ei*0clb32M{tK}G?k4AuvmHBiZ=1r4ezwaK>rQDKjHk>>B&IqFK-|)GIhWl<1Yfd zdy<;^tYBY4>GJtwasSku7shs3CD2wg>-SwkGhL>88~E^Eqq#Y$lDaljj9l)z#!V%R zuys}(p7LfO%0c7V`U6&RyUgVlf+tie;|0G#$7={k*EzK(=aFBZZI|B~+$t7%J1OkW z`^aaonwN+8FWvP|wFaw%ht5fdbVi>r0!>frTB0vICf8q19M!keMLg)dq8*IuOe{V@ zgM3VGM(Z7$@%VQL6_rFsfoVe^H|A8bIr46#IMhdsx3-1~Ku(PmVd!BKQ2}B-9u1q+ zq3z}f=Ba@T5IPL3DcymNhUwZOthcxCr~oG8W;-RUYLHg+NIk3cz*|b_^^@-j>*}g97HO0Jf=j|H?t=>HR z-S&nGGB{GH;*&fUX+mU8Ube0w%dws&rxvr1d-^G9#dQ{N)a|#;&ijG#h-*f^8TDT} zXr`yz;)fw@Gay)6I*;GgjZl-Yee1C-fM}^xb8@d?&B@RB_J>8_C(&j8Z+bkx832Z7 z=CJ_Nt`^JF2(Fa7lIUA_;x5ydM&U)bj!yxDqVhg1W2Y+qHTfYU^)UI4*h{ap`+Tw6 z>QY@_-$&AQEZR!S-v@_lKk(`L7|Mt(ZIJeMwm@KEfZH46(Vsymkm-1Efeitv}u z>SR~dnMj3-kzl`L5ygY957}Xn>_lJ;>vV#0h+y}{Vw)%f12L5i!O6Ty1|%~c>Gb58 z#-}Fm5AX#|A2NK~1CaxfUNf@3=@S-W0pXVezU@tJ~6P-n3mkXm;TU%(J`D~g>X zBm1C3Lm&x}q#( zjbK01GeGSz;iR%f5>xIoCBKDESno_uKEsD&#>dQ!;Ptrr2%8kSL%A|SI92b{tPHEX zzC2&;sbIqSj$;pn%q-xLVgXu^A^>>CkujWdC3C+BEgg;fS0?+bO`b^Zn%9@CIzgqv0zwZ^fGUmOuSv)hBG^aUO zsKX9~90dKTyIWVD)ZAMhY}?pzZ)rN~rN<}O|8HpMIkruleq9SU{0$j(Dcee{ynw*! z744ASI-LOse#UcRllk>Kp4UZuWWvAUsa2cZqvUEufzCSGwB}1Am9JHq4Nyi?zr2XQ z>MFv3v#hhVXr$OPwT!jV`g%PEq8#>6qOh>S zOhb1fB;zYCLGPppo2n*BiK^durRj@I%B(aHOBfm3OI3~rg+g<{pkl8#D^6F-O$q1J z`_$XT(|%`znf=8bUFLxqHWec7Ha4j4r}V4Di)7QFoC6EQLW#XOHo@L^J5k!BP()rq z*X^u9xe&2m6QVko&Q_gvZ`DVtIJy|>fr<`n5C<^i^2Tu)QzC6;8A{Y)-UI_AYXh)1 zA#R<;f*%Y$W-@Mzgv(S~Ek-&W^QDtPAEl-8z0)UU{@hGD`r7uOXW9oG5`6G(#YCE7 z3$7(S^f;CrQ)jiVxep=i-CR-#;)_A$CTnVXM1zJH11fIrBS~w$$BiEPzGg44N9v~p zUv~cf-55x?d$LPTvxn<7%jC2fy;nTOY~Go7jCRb^ki!G1Rm`{SP* z1&U%3fT73P0&M^~6?%uXG6JAhn3cn5&Z9#+&eY&;fh^3)PW_sZsBbQV6mEoDTf9u{ zQ*5XGnev+jSp5;Lbs8yZx>OSjfOYG#wRBd_fwcyekDG9_(PHr68eq`>EoqHVkA2jo=(EoE9)^-Z z6}}%mcZ|CfiKHUlAxtNRW7gNd`!gP%V^~JmUcim;J?Er#g$c6G;C|@bxs@K?#+wl{ z-Qil#Q0=uS$!fd4U=b%HEx0zfO{6)RGc)WE!MyzN5*-y|m;1SL_TNtN>P(0e3RyNJ zS@Et5!=Pk898c%Y2ukg}A=*Xv9cB-m{XWO9+?dvkAkfJ2EA1WeJsoR&5IV65yC}o70Uz_ z?|KbMI1V1HQx&0qLz913Pwzfo;{((k5tOVyay<=YO+K>^bq})ur*I>)zpgb>RFs+k z9V3CbiRwD%m8cI{9tJK$$v#eWq+tak`iJ_gt{5Ayy`GK!{_gT!jH56-J$Azviv$Pi zT}Zd;)*h{|)7J%?LR4Vf$s&8*Mq>zYQV_{Kc7sXdbGpS3O%VCXphH5Z;+utUbMo7F zMC=mO;SV@@@0+{&C#H1icfc1T6=`fLuS(dRDuciq+$qTr)$>~_G$wF6*6iWoBv9NB<+y`bLiO8e+4BUfx-)1TOjPS!-t z^Hmv0Iqb{#y##4&Y6P1a^;P5s zOOSOQnXK(nX0vX3kEMps`ORszIu_bJ@?+a^BD;;32KkG1dNa5RqB_8vk#@kIEFCuK z;x>j1znf27>==_VV239Aic8V=&v&3lt{x&Gx~YBDdXNvrL`E%{(B_izKIV5eu`Y}r zW6qmX9l18sG4b;T>8!!MXqv2*pYwcna^C=_$dGW? zARY{F>z@FQpLB;tS#Wz`66qF)qHE%1`omdx(w1CzU7gR0_x+@P5It?^>)?|}mj&P8 zwSY-S#vj_TMt7xpOo8+knu5_ovG+^Lq<8G`R29nEUmk`(f)k=m|*?5>_Y6fzyw2{dpZQ!9i-aQv-|Ox zgkpQ|7V==;d-b&6kh#iCO2*jreBG64I6Nmu9I~>O*7DP@Z=j%GM7I>>q(YRee`h`q zpszL*;Lg#kL*DOZu8mM4KGvOfc5Y@uc$XDgU@DF}9pViJV$g+4gX_sf_L%2V6YbKl zXuUAi-7qXZ9%<=%O+j&evQ%5s?_FSb!bcIpM+YSaGfy|)#>+&vjKvwX!$eV|eLm15 zU*y;A2c&Tc`ni~j(E@n`of>AG@CI@MSFWga3b40%_=DTKz1cz3OvGl%l$f4vv&yru zDDd}Kv35cFWyY#!AzqT?4X0j0=}B`p9lAd7*Td8)Yq`*)_o@ky$dt(8tBn2_qpi{6 za$ZS{`R)|+mX=}=r-Bel1}roUOr}8f#~2Lws2hP~zp9%c*v$TRJVUz4=9nBM#W5OK z=E$D`@nk1UT>^3Ia2p47(%w3hY%JELbB5|5t1DxM0P5W)(9~#V^l(o)F!$~39l3-k z&Q4gdn)QA`uiW(w`4WmCFh?A}>ECLh-5$>Ao5}-;j4V7#?H3!*p@N#KtELmNKg`~k z$Y)Ob#mUQx7j1u=-QMeo?9|_cyi#(_Wr0w}0Z(qKq%gci+C5-4a;zsVtj9ZvS8&C! zH}sN;8Qt%Gm**_SD%Vx>y++dAWkIA8>a7zUaWLP9tHNzKkK`*V@A_KMn%^e_A|?QK zhN)uRmx@J#F>|*D+vNu^9%Oo)bxDPRsr4WG!usreOOFkC#vtCXjQ~1!R5s9ks7tqv z43~WfF8I}vmWmh5mmR79?+H|O_NOOnEw5zM!|XefGp0c0?9_sTr5|OwPLsxKC=JS~ zWzv2qESl(8G$Oi~G^(lo1!@xv#-6QZTcPr&*+a?bAPcIM&a<^NtF;6Rb*rQa-p=@O zW~52U z)MfLL=OT_bFTDK2N&)Z))|ps;z?)1o4HO%|`i#ENv8rw__3l-0;b9Ngf?TI8FEm(* zBN*?ed`>AsJ{sf2drO>Q2qs6>Inv8Q8|A+`udIUcRcI(d)#+_F2xXEo5=DH->Lz>& ztpU#^+>Phob2g!#WX#IS?MuGRjr7Tgj&VM9YM4GJOq`YJHTp#CKBef_c{$#S#nC*s z{l$9+>5;goC!yE0gw!rn7BzF6|C0S|yRErUd+v4@=bi@b#(0D`gm$w>^=je}A`VtjLb?wg5?k1yweZm%ut*r9o5X)>ybl z|FJ7>{wm=$8lKj*&;&GV$X5w7_-mLFmkWX`OXY)+ndVAH+BrOBkXoZWwK|;Q$`MK-CFVi;V zpkR-qm0_CoFU8O}Eq}C_e!Fzy^3%fg7OB)|D>@I&Ue+R-DN_4q-Wu~@sEri$t-R9?8Fct~rJ)KQPwkCO{t zz-TartT0-w!>_4z?Mc=wM+#8wA;5sPB~m2jv4SeW_%vr9c}|#F`=K&V7tD9@gz%jLH!8VMzkXJuW#^ z(dGOduddyQHf)b;=i35HMTM>v*V21#EYy##6isMhY?e7&{xho%AE$s3E&s$T>{nAK z4etbO$gS9|WI8+(UpTodKB{By)~%_9eoD2 zgm+*KKyJA{?hou^8-*l6jt>!}ACb&*DK+P|-+%looiwCUs68~S6Okv#Dv>n6(MF>G zNxcnlW7Q|?o1O?<^Y8=9YH_+D-G4W&c~r}2mHjjH8r^fskfKE;nURTMSVJn`nM!u=n31)?+#?IA&{a7u*iQkVa0;PGu{v;kp$%yM%)+QZMk`Zw$qdR1I zCeVVaugkWD{9*+DIFVr07HoJ^%UohiNnsLN){bs+;_=<+a zXay7Mw#GAS&a$(02;j->_+deUg*FZHyV+YaC_Tu7s_}^TN_lSf1@SV;o2p|0Aj5`L zlFIs~#NhzE%Jr(IWg8#4j<7$A|8)*SY?91Uz8;35aT}_#^niGMD@Cb)(q<1|{)`1u z57f82n9NWA7$*v6h^kL~3A8>W#YuhqnxA}Q3h>P#rRt*s$mX6!T~_Ow>J0pikMSgp zTcf6BnBxp!gHcVBuT@^p1%U+%_R!oPB~<)Ck;6|0Sc_U;-ES|d#mPotg*SX_Sq7j( z*~N&1m7j~hx_`g-?Lw+wTIAKwPC*pItUHGxN5Qv?dl6fy>s3L^gtFvaQLe=nCjE!$ zp~f1=BVDa(Es6RKs8v>9F`Rl>?DBwc)4lL;S-%=_wY6o8INp9Rld@Q>-1Bsb^68Td zm3@o2N^+T3nhX9I#ay_A#C4Vfkn7)>y#DWhkPm~_XchdCKjFXEv(rw&TbtBC0 z|E4(*(X<<0iSaT0#rP-7y0hmDS*Gsi&@ZD=x3+zo6h~~kjz&W9^4PJR;27;fHTL6| z^bwX=BDQZq794e?69(O5ahvk5&8#zlgZ^*bMsE-D$0!3)Dt)x218Eyay8hWKQU*9i z8J6iSQ{YnmhVGJu&gxy0w;OT{&=izWE42}5G?2~Mb#P~j*#xA1F&`Ajq7&I=fKEIV zUa4p33okFLlo3CRW~PV(-2B#`i#HXk+(*gniu`gPauG*AA|b8ruPM}lEMx;cP-WcF)QPXh|z~#jD?QT)U`Oa z#w{(oU0|QzhZt1m9r?Ffqt7#MLHPW2)UZRwH_*bJ7gaD{3c4o7ms_i$%vZfi*=UQ6Gt>9mkrxG<{tCXU`Kl4 zo9Ak-sq%5ho|<7@jPgr`6**7(K=*Y#uQ#S7psXKYR;*1y{#PA$oS)iOnR@M@eBXLF zs}*`&dpB&lOhM^#lwV{p7BYsd{^39B%8cmin~dohqb_~=;zHJ$Qln$H+>c3X9+QwD z-uLz1gZHG=@$%$d2WSLl#MbENYWx4-(Eoql)sNHr#?9=;rxeB=0!?j;!Xj4aAy|ui z`_%5^2Fk9|R#*gw%E{eTF8emJ@@=MX;x;KQb+M39%P`a8-`;%rBkxvinWv)Z^UfWY zK6K}?(V{&!qD;(o%idFBGuiEQ5>7Uyi3`HoXGmS)Sligjb~OE$d6G&i3EM(>|S z1;O8KV8A7oL9t(00lP~qAS1C+7g}T13t-I-;CUMpOFkE3A6dI&exFZur)|a$Ad)3rb*zEs{;vm>c4X*{{8P?ODB$>{|{ADN~r(< literal 0 HcmV?d00001 diff --git a/Tests/IM-0001-0019.dcm b/Tests/IM-0001-0019.dcm new file mode 100644 index 0000000000000000000000000000000000000000..158830614412f87872388317443d3bca59571f66 GIT binary patch literal 240874 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%0DuAKj57BFi;`tLs7Jm(n$m+K}+?=g+ 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

3o?;-^aQPb<}AhX0sJrbT^%4an3rU(cOgb;!>? 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 +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Tests { + using System; + + + ///

+ /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class TestDicomFiles { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal TestDicomFiles() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Tests.TestDicomFiles", typeof(TestDicomFiles).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] IM_0001_0013 { + get { + object obj = ResourceManager.GetObject("IM_0001_0013", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] IM_0001_0019 { + get { + object obj = ResourceManager.GetObject("IM_0001_0019", resourceCulture); + return ((byte[])(obj)); + } + } + } +} diff --git a/TemplateBuilder/Repopulator/RepopulatorUI.resx b/Tests/TestDicomFiles.resx similarity index 90% rename from TemplateBuilder/Repopulator/RepopulatorUI.resx rename to Tests/TestDicomFiles.resx index 1f666f2..583e8d0 100644 --- a/TemplateBuilder/Repopulator/RepopulatorUI.resx +++ b/Tests/TestDicomFiles.resx @@ -117,7 +117,11 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - 17, 17 - + + + IM-0001-0013.dcm;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + IM-0001-0019.dcm;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + \ No newline at end of file diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index 72f9d0f..f5ae710 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -14,13 +14,42 @@ - - - - - + + + + + + + True + True + TestDicomFiles.resx + + + + + ResXFileCodeGenerator + TestDicomFiles.Designer.cs + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + \ No newline at end of file diff --git a/Tests/TwoSeriesCsv.csv b/Tests/TwoSeriesCsv.csv new file mode 100644 index 0000000..f464897 --- /dev/null +++ b/Tests/TwoSeriesCsv.csv @@ -0,0 +1,3 @@ +SeriesInstanceUID,ID +1.2.394,NewPatientID1 +1.2.840.113619.2.176.2025.1499492.7391.1171285944.394,NewPatientID2 diff --git a/Tests/WithDate.csv b/Tests/WithDate.csv new file mode 100644 index 0000000..9f1505a --- /dev/null +++ b/Tests/WithDate.csv @@ -0,0 +1,2 @@ +SeriesInstanceUID,ID,Date +1.2.394, NewPatientID1, 20180601 From 6c974fd9f15697c464a5e60807bec51d2bc4b63b Mon Sep 17 00:00:00 2001 From: Thomas Nind Date: Mon, 28 Oct 2019 10:14:17 +0000 Subject: [PATCH 07/19] Added implementation logic for matchers. All tests now passing --- Repopulator/CsvToDicomTagMapping.cs | 116 +++++++++++++++----- Repopulator/DicomRepopulatorOptions.cs | 6 +- Repopulator/DicomRepopulatorProcessor.cs | 79 +++++++------ Repopulator/IFindFilesForRows.cs | 42 ------- Repopulator/Matchers/FilePathMatcher.cs | 37 +++++++ Repopulator/Matchers/IRepopulatorMatcher.cs | 15 +++ Repopulator/Matchers/MatcherFactory.cs | 25 +++++ Repopulator/Matchers/RepopulatorMatcher.cs | 24 ++++ Repopulator/Matchers/TagMatcher.cs | 100 +++++++++++++++++ Repopulator/RepopulatorJob.cs | 20 ++++ TemplateBuilder/RepopulatorUI.cs | 1 + Tests/CsvToDicomColumnTests.cs | 9 +- Tests/DicomRepopulatorTests.cs | 2 +- 13 files changed, 356 insertions(+), 120 deletions(-) delete mode 100644 Repopulator/IFindFilesForRows.cs create mode 100644 Repopulator/Matchers/FilePathMatcher.cs create mode 100644 Repopulator/Matchers/IRepopulatorMatcher.cs create mode 100644 Repopulator/Matchers/MatcherFactory.cs create mode 100644 Repopulator/Matchers/RepopulatorMatcher.cs create mode 100644 Repopulator/Matchers/TagMatcher.cs create mode 100644 Repopulator/RepopulatorJob.cs diff --git a/Repopulator/CsvToDicomTagMapping.cs b/Repopulator/CsvToDicomTagMapping.cs index 6595046..81003c1 100644 --- a/Repopulator/CsvToDicomTagMapping.cs +++ b/Repopulator/CsvToDicomTagMapping.cs @@ -6,13 +6,12 @@ using CsvHelper; using CsvHelper.Configuration; using Dicom; +using Repopulator.Matchers; namespace Repopulator { public class CsvToDicomTagMapping { - - /// /// The column of the CSV which records the file path to the image(s) being processed. These should be expressed /// relatively (i.e. not absolute path names) @@ -38,23 +37,35 @@ public void Clear() FilenameColumn = null; CsvFile = null; TagColumns.Clear(); + IsBuilt = false; } /// - /// Reads the headers from the CSV specified in and builds and . + /// True if the class has been built yet + /// + public bool IsBuilt { get; private set; } + + /// + /// Reads the headers from the CSV specified in and builds and . /// Returns true if the headers constitute a valid set (at least 1 and found). /// - /// + /// /// /// - public bool BuildMap(DicomRepopulatorOptions state, out string log) + public bool BuildMap(DicomRepopulatorOptions options, out string log) { Clear(); StringBuilder sb = new StringBuilder(); + + //how we will tie CSV rows to files + IRepopulatorMatcher matcher = null; + try { - CsvFile = state.CsvFileInfo; + var extraMappings = GetExtraMappings(options); + + CsvFile = options.CsvFileInfo; using (var reader = new CsvReader(CsvFile.OpenText())) { @@ -69,7 +80,7 @@ public bool BuildMap(DicomRepopulatorOptions state, out string log) for (var index = 0; index < reader.Context.HeaderRecord.Length; index++) { var header = reader.Context.HeaderRecord[index]; - var match = GetKeyDicomTagAndColumnName(state, header, index); + var match = GetKeyDicomTagAndColumnName(options, header, index,extraMappings); if (match != null) { @@ -86,7 +97,7 @@ public bool BuildMap(DicomRepopulatorOptions state, out string log) TagColumns.Add(match); } - sb.AppendLine($"Validated header ''{header}''"); + sb.AppendLine($"Validated header '{header}'"); } else sb.AppendLine($"Could not determine tag for '{header}'"); @@ -96,6 +107,12 @@ public bool BuildMap(DicomRepopulatorOptions state, out string log) sb.AppendLine($"Found {TagColumns.Count} valid mappings"); sb.AppendLine($"FilenameColumn is: {FilenameColumn?.Name ?? "Not Set"}"); } + + IsBuilt = true; + + var matcherFactory = new MatcherFactory(); + matcher = matcherFactory.Create(this,options); + sb.AppendLine($"Matching Strategy is: { matcher?.ToString() ?? "No Strategy Found"}"); } catch (Exception e) { @@ -103,36 +120,77 @@ public bool BuildMap(DicomRepopulatorOptions state, out string log) log = sb.ToString(); return false; } - + log = sb.ToString(); - return TagColumns.Count > 0 && FilenameColumn != null; + + + return TagColumns.Count > 0 && matcher != null; } - /// - /// Get the key DicomTag and associated CSV column name. - /// - public CsvToDicomColumn GetKeyDicomTagAndColumnName(DicomRepopulatorOptions state, string columnName,int index) + + + private Dictionary> GetExtraMappings(DicomRepopulatorOptions state) { - if(columnName.Equals(state.FileNameColumn,StringComparison.CurrentCultureIgnoreCase)) - return new CsvToDicomColumn(columnName,index,true); + Dictionary> toReturn = new Dictionary>(StringComparer.CurrentCultureIgnoreCase); - string[] split = columnName.Split(':'); - if (split.Length == 1) + if(string.IsNullOrWhiteSpace(state.InputExtraMappings)) + return null; + + var extraMappingsFile = state.ExtraMappings; + + int lineNumber = 0; + foreach (string[] pair in File.ReadAllLines(extraMappingsFile.FullName).Select(l => l.Split(new []{':'},StringSplitOptions.RemoveEmptyEntries))) { - var found = DicomDictionary.Default.SingleOrDefault(entry => string.Equals(entry.Keyword ,columnName,StringComparison.CurrentCultureIgnoreCase)); - return found != null ? new CsvToDicomColumn(columnName,index,false,found.Tag) : null; + lineNumber++; + + //ignore blank lines + if(pair.Length == 0) + continue; + + if(pair.Length != 2) + throw new Exception($"Bad line in extra mappings file (line number {lineNumber}). Line did not match expected format 'ColumnName:TagName'"); + + + var found = DicomDictionary.Default.SingleOrDefault(entry => string.Equals(entry.Keyword ,pair[1],StringComparison.CurrentCultureIgnoreCase)); + + if (found == null) + throw new Exception( + $"Bad tag '{pair[1]}' on line number {lineNumber} of ExtraMappings file '{extraMappingsFile.FullName}'. It is not a valid DicomTag name"); + + if(!toReturn.ContainsKey(pair[0])) + toReturn.Add(pair[0],new HashSet()); + + toReturn[pair[0]].Add(found.Tag); } - - if(split.Length != 2 || split[0].Length == 0 || split[1].Length == 0) - return null; - - string dicomTagString = split[1]; - // Check the DICOM tag is a valid DICOM tag - var found2 = - DicomDictionary.Default.SingleOrDefault(entry => string.Equals(entry.Keyword ,dicomTagString,StringComparison.CurrentCultureIgnoreCase)); + return toReturn; + } - return found2 != null ? new CsvToDicomColumn(columnName, index,false, found2.Tag) : null; + /// + /// Creates a mapping between a single CSV file column and one or more + /// + public CsvToDicomColumn GetKeyDicomTagAndColumnName(DicomRepopulatorOptions state, string columnName,int index,Dictionary> extraMappings) + { + CsvToDicomColumn toReturn = null; + if(columnName.Equals(state.FileNameColumn,StringComparison.CurrentCultureIgnoreCase)) + toReturn = new CsvToDicomColumn(columnName,index,true); + + var found = DicomDictionary.Default.SingleOrDefault(entry => string.Equals(entry.Keyword ,columnName,StringComparison.CurrentCultureIgnoreCase)); + + if(found != null) + if (toReturn == null) + toReturn = new CsvToDicomColumn(columnName,index,false,found.Tag); + else + toReturn.TagsToPopulate.Add(found.Tag); //it's a file path AND a tag! ok... + + + if (extraMappings != null && extraMappings.ContainsKey(columnName)) + if(toReturn == null) + toReturn = new CsvToDicomColumn(columnName,index,false,extraMappings[columnName].ToArray()); + else + toReturn.TagsToPopulate.UnionWith(extraMappings[columnName]); + + return toReturn; } } } diff --git a/Repopulator/DicomRepopulatorOptions.cs b/Repopulator/DicomRepopulatorOptions.cs index b5e28a5..d9c6e71 100644 --- a/Repopulator/DicomRepopulatorOptions.cs +++ b/Repopulator/DicomRepopulatorOptions.cs @@ -11,8 +11,8 @@ public class DicomRepopulatorOptions public string InputExtraMappings; public string OutputFolder; public int NumThreads; - public bool IncludeSubdirectories; - public string Pattern; + public bool IncludeSubdirectories = true; + public string Pattern = "*.dcm"; public string FileNameColumn = ImagingTableCreation.RelativeFileArchiveURI; public bool Anonymise; @@ -25,6 +25,8 @@ public class DicomRepopulatorOptions [YamlIgnore] public FileInfo CsvFileInfo => new FileInfo(InputCsv); + [YamlIgnore] + public FileInfo ExtraMappings => new FileInfo(InputExtraMappings); } } \ No newline at end of file diff --git a/Repopulator/DicomRepopulatorProcessor.cs b/Repopulator/DicomRepopulatorProcessor.cs index 431a5bb..e5745c7 100644 --- a/Repopulator/DicomRepopulatorProcessor.cs +++ b/Repopulator/DicomRepopulatorProcessor.cs @@ -9,7 +9,9 @@ using Dicom; using DicomTypeTranslation.Helpers; using NLog; +using NLog.Config; using NLog.Targets; +using Repopulator.Matchers; namespace Repopulator { @@ -25,9 +27,9 @@ public class DicomRepopulatorProcessor private ParallelOptions _parallelOptions; - public IRepopulatorMatcher Matcher { get; } + public IRepopulatorMatcher Matcher { get; private set; } - public MemoryTarget MemoryLogTarget { get; } = new MemoryTarget(); + public MemoryTarget MemoryLogTarget { get; } = new MemoryTarget(){Name = "DicomRepopulatorProcessor_Memory"}; public int Done { get; private set; } public int Errors { get; private set; } @@ -37,7 +39,9 @@ public DicomRepopulatorProcessor(string currentDirectory = null) if(File.Exists(log)) LogManager.Configuration = new NLog.Config.XmlLoggingConfiguration(log, false); - + else + LogManager.Configuration = new LoggingConfiguration(); + LogManager.Configuration.AddTarget(MemoryLogTarget); _logger = LogManager.GetCurrentClassLogger(); @@ -52,6 +56,9 @@ public int Process(DicomRepopulatorOptions options) { _parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = options.NumThreads }; + if(!options.OutputDirectoryInfo.Exists) + options.OutputDirectoryInfo.Create(); + _logger.Debug("Checking output directory for contents"); if (options.OutputDirectoryInfo.EnumerateFileSystemInfos().Any()) { @@ -67,7 +74,7 @@ public int Process(DicomRepopulatorOptions options) try { if(!map.BuildMap(options,out string log)) - throw new Exception("Failed to build map"); + throw new Exception("Failed to build map:" + log); _logger.Info("Map built succesfully:" + log); } @@ -80,48 +87,21 @@ public int Process(DicomRepopulatorOptions options) var csvFile = options.CsvFileInfo; _logger.Info("Starting " + csvFile.FullName); + var factory = new MatcherFactory(); + + Matcher = factory.Create(map, options); + + if (Matcher == null) + throw new Exception("No suitable IRepopulatorMatcher could be built, ensure you have either file paths or instance UIDs in your csv file / extra mappings (otherwise we have no way to match rows to files)"); + RepopulatorJob job; //while there are more jobs while ((job = Matcher.Next()) != null) { - ProcessJob(job); - } - - /* - //now process each row in the CSV and find matching files - using (var reader = new CsvReader(csvFile.OpenText())) - { - reader.Configuration.TrimOptions = TrimOptions.Trim; - while (reader.Read()) - { - var files = - - if (files == null || files.Length == 0) - { - Errors++; - Error("No files found for row", reader.Context.RawRow); - } - else - foreach (var f in files) - { - RePopulate(f, map,reader.Context.RawRow); - Done++; - } - } - } - */ - - try - { - ProcessDicomFiles(options, map); + ProcessJob(job,options); } - catch (Exception e) - { - _logger.Error("Exception processing dicom files: " + e.Message); - return -1; - } - + var sb = new StringBuilder(); sb.AppendLine("\n=== Finished processing ==="); sb.AppendLine("Total input files: " + _nInput); @@ -135,9 +115,24 @@ public int Process(DicomRepopulatorOptions options) return 0; } - private void ProcessJob(RepopulatorJob job) + private void ProcessJob(RepopulatorJob job, DicomRepopulatorOptions options) { - throw new NotImplementedException(); + foreach (var col in job.Map.TagColumns) + foreach (DicomTag dicomTag in col.TagsToPopulate) + job.File.Dataset.AddOrUpdate(dicomTag, job.Cells[col.Index]); + + //the relative location in the archive + var inputRelativePath = + job.File.File.Name.Replace(options.DirectoryToProcessInfo.FullName, "").TrimStart(Path.DirectorySeparatorChar); + + _logger.Debug("Saving output file"); + + // Preserves any sub-directory structures + var outPath = Path.Combine(options.OutputDirectoryInfo.FullName, inputRelativePath); + Directory.CreateDirectory(Path.GetDirectoryName(outPath)); + + job.File.Save(outPath); + } private void Error(string problemDescription, int lineNumber) diff --git a/Repopulator/IFindFilesForRows.cs b/Repopulator/IFindFilesForRows.cs deleted file mode 100644 index dd8a793..0000000 --- a/Repopulator/IFindFilesForRows.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System.IO; - -namespace Repopulator -{ - /// - /// Interface for classes that match Csv rows to files on disk. This could be as simple as following a file URI or as - /// complicated as reading a UID returning the corresponding files - /// - public interface IRepopulatorMatcher - { - /// - /// Returns the next file to be repopulated and the corresponding values to overwrite with. Returns - /// null if there are no more files/rows to process - /// - RepopulatorJob Next(); - } - - public class FilePathMatcher - { - protected DicomRepopulatorOptions Args { get; } - protected CsvToDicomTagMapping Map { get; } - - public FilePathMatcher(CsvToDicomTagMapping map, DicomRepopulatorOptions args) - { - Args = args; - Map = map; - } - } - - public class RepopulatorJob - { - public CsvToDicomTagMapping Map { get; } - public FileInfo File { get; } - public string[] Cells { get; set; } - public RepopulatorJob( CsvToDicomTagMapping map,FileInfo file, string[] cells) - { - File = file; - Map = map; - Cells = cells; - } - } -} diff --git a/Repopulator/Matchers/FilePathMatcher.cs b/Repopulator/Matchers/FilePathMatcher.cs new file mode 100644 index 0000000..77be613 --- /dev/null +++ b/Repopulator/Matchers/FilePathMatcher.cs @@ -0,0 +1,37 @@ +using System; +using System.IO; +using CsvHelper; +using CsvHelper.Configuration; +using Dicom; + +namespace Repopulator.Matchers +{ + public class FilePathMatcher: RepopulatorMatcher + { + public CsvReader Reader { get;} + + public FilePathMatcher(CsvToDicomTagMapping map, DicomRepopulatorOptions options):base(map,options) + { + if(map.FilenameColumn == null) + throw new ArgumentException("Map did not contain file name column"); + + Reader = new CsvReader(map.CsvFile.OpenText()); + Reader.Configuration.TrimOptions = TrimOptions.Trim; + } + + public override RepopulatorJob Next() + { + if (!Reader.Read()) + return null; + + var fi = new FileInfo(Path.Combine(Options.InputFolder, Reader[Map.FilenameColumn.Index])); + + return new RepopulatorJob(Map,DicomFile.Open(fi.FullName),Reader.Context.Record); + } + + public override void Dispose() + { + Reader.Dispose(); + } + } +} diff --git a/Repopulator/Matchers/IRepopulatorMatcher.cs b/Repopulator/Matchers/IRepopulatorMatcher.cs new file mode 100644 index 0000000..edf0ea3 --- /dev/null +++ b/Repopulator/Matchers/IRepopulatorMatcher.cs @@ -0,0 +1,15 @@ +namespace Repopulator.Matchers +{ + /// + /// Interface for classes that match Csv rows to files on disk. This could be as simple as following a file URI or as + /// complicated as reading a UID returning the corresponding files + /// + public interface IRepopulatorMatcher + { + /// + /// Returns the next file to be repopulated and the corresponding values to overwrite with. Returns + /// null if there are no more files/rows to process + /// + RepopulatorJob Next(); + } +} \ No newline at end of file diff --git a/Repopulator/Matchers/MatcherFactory.cs b/Repopulator/Matchers/MatcherFactory.cs new file mode 100644 index 0000000..2fc091f --- /dev/null +++ b/Repopulator/Matchers/MatcherFactory.cs @@ -0,0 +1,25 @@ +using System.Linq; +using Dicom; + +namespace Repopulator.Matchers +{ + public class MatcherFactory + { + public IRepopulatorMatcher Create(CsvToDicomTagMapping map, DicomRepopulatorOptions options) + { + //We have a column that contains the exact location on disk of the image. This is the best because it lets us stream the CSV + if(map.FilenameColumn != null) + return new FilePathMatcher(map,options); + + //We have no file path column so must do matching based on 'key'. This will require loading entire CSV into memory which may break + //for very large datasets + if (map.TagColumns.Any(c => + c.TagsToPopulate.Contains(DicomTag.SOPInstanceUID) || + c.TagsToPopulate.Contains(DicomTag.SeriesInstanceUID) || + c.TagsToPopulate.Contains(DicomTag.StudyInstanceUID))) + return new TagMatcher(map, options); + + return null; + } + } +} \ No newline at end of file diff --git a/Repopulator/Matchers/RepopulatorMatcher.cs b/Repopulator/Matchers/RepopulatorMatcher.cs new file mode 100644 index 0000000..12633ef --- /dev/null +++ b/Repopulator/Matchers/RepopulatorMatcher.cs @@ -0,0 +1,24 @@ +using System; + +namespace Repopulator.Matchers +{ + public abstract class RepopulatorMatcher : IRepopulatorMatcher, IDisposable + { + protected DicomRepopulatorOptions Options { get; } + protected CsvToDicomTagMapping Map { get; } + public RepopulatorMatcher(CsvToDicomTagMapping map, DicomRepopulatorOptions options) + { + Options = options; + Map = map; + + if(!Map.IsBuilt) + throw new ArgumentException("Map has not been built yet"); + + if(string.IsNullOrWhiteSpace(options.InputFolder)) + throw new ArgumentException("InputFolder has not been set"); + } + + public abstract RepopulatorJob Next(); + public abstract void Dispose(); + } +} \ No newline at end of file diff --git a/Repopulator/Matchers/TagMatcher.cs b/Repopulator/Matchers/TagMatcher.cs new file mode 100644 index 0000000..3327b20 --- /dev/null +++ b/Repopulator/Matchers/TagMatcher.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using CsvHelper; +using CsvHelper.Configuration; +using Dicom; + +namespace Repopulator.Matchers +{ + /// + /// Matcher that reads the entire CSV file and builds a map of UIDs to rows at a granularity of either sop, series or study + /// + internal class TagMatcher : RepopulatorMatcher + { + private string[] _fileList; + private int _currentFile = 0; + + private CsvToDicomColumn _indexer; + private DicomTag _indexerTag; + + /// + /// Map of all the InstanceUIDs described in the CSV and the row values on that CSV line + /// + Dictionary _indexerToRowMap = new Dictionary(); + + public TagMatcher(CsvToDicomTagMapping map, DicomRepopulatorOptions options):base(map,options) + { + _fileList = Directory.GetFiles(options.InputFolder, options.Pattern, + options.IncludeSubdirectories? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly); + + _indexer = GetBestIndexer(map); + + if(_indexer == null) + throw new ArgumentException("No valid indexer could be found, there must be a column in the map for either SOP, Series or Study instance UIDs"); + + using (var reader = new CsvReader(map.CsvFile.OpenText())) + { + reader.Configuration.TrimOptions = TrimOptions.Trim; + + while (reader.Read()) + { + string key = reader[_indexer.Index]; + + if(_indexerToRowMap.ContainsKey(key)) + throw new Exception($"Multiple Csv rows describe the same '{_indexerTag}' '{key}'. Error was on CSV line number '{reader.Context.RawRow}'"); + + _indexerToRowMap.Add(key,reader.Context.Record.ToArray()); + } + } + } + + private CsvToDicomColumn GetBestIndexer(CsvToDicomTagMapping map) + { + return + GetIndexer(map,DicomTag.SOPInstanceUID)?? + GetIndexer(map,DicomTag.SeriesInstanceUID)?? + GetIndexer(map,DicomTag.StudyInstanceUID); + } + + private CsvToDicomColumn GetIndexer(CsvToDicomTagMapping map, DicomTag tag) + { + var match = map.TagColumns.FirstOrDefault(c => c.TagsToPopulate.Contains(tag)); + + if (match == null) + return null; + + _indexerTag = tag; + + return match; + } + + public override RepopulatorJob Next() + { + //we have run out of files to process + if (_currentFile >= _fileList.Length) + return null; + + try + { + var df = DicomFile.Open(_fileList[_currentFile]); + var seek = df.Dataset.GetValue(_indexerTag, 0); + + if(!_indexerToRowMap.ContainsKey(seek)) + throw new Exception($"Csv did not contain a value for {_indexerTag} {seek} which was found in file '{_fileList[_currentFile]}'"); + + return new RepopulatorJob(Map,df,_indexerToRowMap[seek]); + } + finally + { + _currentFile++; + } + } + + public override void Dispose() + { + + } + } +} \ No newline at end of file diff --git a/Repopulator/RepopulatorJob.cs b/Repopulator/RepopulatorJob.cs new file mode 100644 index 0000000..cd220f9 --- /dev/null +++ b/Repopulator/RepopulatorJob.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using System.IO; +using Dicom; +using Repopulator.Matchers; + +namespace Repopulator +{ + public class RepopulatorJob + { + public CsvToDicomTagMapping Map { get; } + public DicomFile File { get; } + public string[] Cells { get; set; } + public RepopulatorJob( CsvToDicomTagMapping map,DicomFile file, string[] cells) + { + File = file; + Map = map; + Cells = cells; + } + } +} \ No newline at end of file diff --git a/TemplateBuilder/RepopulatorUI.cs b/TemplateBuilder/RepopulatorUI.cs index 0d7bbf6..92e8b2b 100644 --- a/TemplateBuilder/RepopulatorUI.cs +++ b/TemplateBuilder/RepopulatorUI.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Windows.Forms; using Repopulator; +using Repopulator.Matchers; using YamlDotNet.Serialization; namespace TemplateBuilder diff --git a/Tests/CsvToDicomColumnTests.cs b/Tests/CsvToDicomColumnTests.cs index 8a7ee8a..02e60c2 100644 --- a/Tests/CsvToDicomColumnTests.cs +++ b/Tests/CsvToDicomColumnTests.cs @@ -2,6 +2,7 @@ using Dicom; using NUnit.Framework; using Repopulator; +using Repopulator.Matchers; namespace Tests { @@ -11,28 +12,28 @@ public class CsvToDicomColumnTests public void NegativeIndex() { var ex = Assert.Throws(() => new CsvToDicomColumn("fish", -1, true)); - StringAssert.Contains("index cannot be negative",ex.Message); + StringAssert.Contains(ex.Message,"index cannot be negative"); } [Test] public void NoClearRole() { var ex = Assert.Throws(() => new CsvToDicomColumn("fish", 0, false)); - StringAssert.Contains(ex.Message,"no clear role"); + StringAssert.Contains("no clear role",ex.Message); } [Test] public void TooManyRoles() { var ex = Assert.Throws(() => new CsvToDicomColumn("fish", 0, true,DicomTag.ALineRate)); - StringAssert.Contains(ex.Message,"has ambiguous role"); + StringAssert.Contains("has ambiguous role",ex.Message); } [Test] public void SequenceTags() { var ex = Assert.Throws(() => new CsvToDicomColumn("fish", 0, false,DicomTag.AbstractPriorCodeSequence)); - StringAssert.Contains(ex.Message,"Sequence tags are not supported (AbstractPriorCodeSequence)"); + StringAssert.Contains("Sequence tags are not supported (AbstractPriorCodeSequence)",ex.Message); } } } diff --git a/Tests/DicomRepopulatorTests.cs b/Tests/DicomRepopulatorTests.cs index 1c04ccd..0bf5659 100644 --- a/Tests/DicomRepopulatorTests.cs +++ b/Tests/DicomRepopulatorTests.cs @@ -80,7 +80,7 @@ public void KeyNotFirstColumn() InputCsv = Path.Combine(TestContext.CurrentContext.TestDirectory, "KeyNotFirstColumn.csv"), InputFolder = inputDirPath, OutputFolder = outputDirPath, - InputExtraMappings = GenerateExtraMappingsFile( "ID:PatientID" ), + InputExtraMappings = GenerateExtraMappingsFile( "ID:PatientID","sopid:SOPInstanceUID" ), NumThreads = 4 }; From 983ab00b1db7b3e62fb2ede51c1cccc425bcb38e Mon Sep 17 00:00:00 2001 From: Thomas Nind Date: Mon, 28 Oct 2019 12:30:26 +0000 Subject: [PATCH 08/19] Improved usability of user interface and added async for Start --- Icons/CopyToClipboard.png | Bin 0 -> 804 bytes Repopulator/DicomRepopulatorOptions.cs | 1 + Repopulator/DicomRepopulatorProcessor.cs | 165 +++-------- Repopulator/Matchers/IRepopulatorMatcher.cs | 2 + Repopulator/Matchers/RepopulatorMatcher.cs | 16 + Repopulator/Matchers/TagMatcher.cs | 10 +- TemplateBuilder/Form1.cs | 3 +- TemplateBuilder/RepopulatorUI.Designer.cs | 312 ++++++++++++-------- TemplateBuilder/RepopulatorUI.cs | 144 +++++++-- TemplateBuilder/RepopulatorUI.resx | 18 ++ Tests/DicomRepopulatorTests.cs | 6 +- 11 files changed, 415 insertions(+), 262 deletions(-) create mode 100644 Icons/CopyToClipboard.png diff --git a/Icons/CopyToClipboard.png b/Icons/CopyToClipboard.png new file mode 100644 index 0000000000000000000000000000000000000000..aad40a918480a5dee22c46ddc2339a51c60a3208 GIT binary patch literal 804 zcmV+<1Ka$GP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0=Y>p|bJ* zvr@0OUeh!fhQXJv>)c6R3cUI-aHYX1fpon_f>7`Ty&b0rv$mot1Vbvyt7>_ms;SUa z6{@O1H*_q`O`$l8z-3y8?fXj{zo`fo7RXRq*A7ov4WiK~p7syGY&L-q#(=<}mN9B< zYK7gFfyIx*FlYh>6Ms{fEmkPX4-5`IN1D|Hi7?@!)cE6QuMs&dOqyl2Jg4 zfk7!|?#V>s#Y_B5%LA*6SzXr~=dZ zjX@BE-3&BHQaa|OK5WK+q5W7db=>~OSU4OGSgj)0gOKg6Fr+jvD1+G67Phnm@^ien z{q_O^fdF5!EF-)g=80HctV266wfFhRwD&h2t=&cE=y~Kg3gC5Dq9D5j-N81vTuwOY zibU2CTn&6Po@~aU|#LzKy7M+zZs4J6?3dmcl zr>Jwwf|r#=d{!19hvpH9DOe86I9lL?$6bNeu{v6Uf($wXygR!X@B|vIKi63Zx3dU& zu0s&b681U{V0vX7V~dmMZ+VB}qGBqt#6{e#flzpjPRw7pdipxvf0@AWr#HCa>83Yq z77XO(x{;loh1J<1@A5Y_>m-{3D0000 new DirectoryInfo(OutputFolder); diff --git a/Repopulator/DicomRepopulatorProcessor.cs b/Repopulator/DicomRepopulatorProcessor.cs index e5745c7..1af72c5 100644 --- a/Repopulator/DicomRepopulatorProcessor.cs +++ b/Repopulator/DicomRepopulatorProcessor.cs @@ -15,23 +15,30 @@ namespace Repopulator { - public class DicomRepopulatorProcessor + public class DicomRepopulatorProcessor: IDisposable { private readonly ILogger _logger; - private int _nInput; - private int _nMatched; - private int _nProcessed; - private Stopwatch _stopwatch; private ParallelOptions _parallelOptions; - + private DicomAnonymizer _anonymizer; + public IRepopulatorMatcher Matcher { get; private set; } public MemoryTarget MemoryLogTarget { get; } = new MemoryTarget(){Name = "DicomRepopulatorProcessor_Memory"}; - public int Done { get; private set; } - public int Errors { get; private set; } + + private int _nInput; + private int _nDone; + private int _nErrors; + + /// + /// The number of images found in the input directory (optionally a recursive scan) + /// + public int Input => _nInput; + + public int Done => _nDone; + public int Errors => _nErrors; public DicomRepopulatorProcessor(string currentDirectory = null) { @@ -42,20 +49,21 @@ public DicomRepopulatorProcessor(string currentDirectory = null) else LogManager.Configuration = new LoggingConfiguration(); - LogManager.Configuration.AddTarget(MemoryLogTarget); + MemoryLogTarget.Layout = "${level} ${message}"; + SimpleConfigurator.ConfigureForTargetLogging(MemoryLogTarget,LogLevel.Trace); _logger = LogManager.GetCurrentClassLogger(); - + if (!DicomDatasetHelpers.CorrectFoDicomVersion()) throw new ApplicationException("Incorrect fo-dicom version for the current platform"); - - MemoryLogTarget.Layout = "${level} ${message}"; } public int Process(DicomRepopulatorOptions options) { _parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = options.NumThreads }; + _anonymizer = options.Anonymise ? new DicomAnonymizer() : null; + if(!options.OutputDirectoryInfo.Exists) options.OutputDirectoryInfo.Create(); @@ -94,19 +102,35 @@ public int Process(DicomRepopulatorOptions options) if (Matcher == null) throw new Exception("No suitable IRepopulatorMatcher could be built, ensure you have either file paths or instance UIDs in your csv file / extra mappings (otherwise we have no way to match rows to files)"); - RepopulatorJob job; + _nInput = Matcher.GetInputFileCount(); + + RepopulatorJob job = null; //while there are more jobs - while ((job = Matcher.Next()) != null) + do { - ProcessJob(job,options); - } + try + { + job = Matcher.Next(); + + if(job != null) + ProcessJob(job, options); + } + catch (Exception e) + { + _logger.Error(e); + Interlocked.Increment(ref _nErrors); + } + } while (job != null && _nErrors < options.ErrorThreshold); + + if(_nErrors >= options.ErrorThreshold) + throw new Exception("Error threshold reached"); var sb = new StringBuilder(); sb.AppendLine("\n=== Finished processing ==="); sb.AppendLine("Total input files: " + _nInput); - sb.AppendLine("Total matched to input data: " + _nMatched); - sb.Append("Total processed: " + _nProcessed); + sb.AppendLine("Total failed: " + _nErrors); + sb.Append("Total processed: " + _nDone); _logger.Info(sb.ToString()); @@ -117,6 +141,9 @@ public int Process(DicomRepopulatorOptions options) private void ProcessJob(RepopulatorJob job, DicomRepopulatorOptions options) { + if(options.Anonymise) + _anonymizer.AnonymizeInPlace(job.File.Dataset); + foreach (var col in job.Map.TagColumns) foreach (DicomTag dicomTag in col.TagsToPopulate) job.File.Dataset.AddOrUpdate(dicomTag, job.Cells[col.Index]); @@ -133,108 +160,14 @@ private void ProcessJob(RepopulatorJob job, DicomRepopulatorOptions options) job.File.Save(outPath); - } - - private void Error(string problemDescription, int lineNumber) - { - _logger.Error($"{problemDescription}:line {lineNumber}"); - } - - - /// - /// Processes the Dicom files and alters the values according to the replacement dictionary. - /// Makes an alternate copy of each Dicom file into the output directory. - /// - /// Options as specified on the command line. - /// contains new values for the tags to be altered. - private void ProcessDicomFiles( - DicomRepopulatorOptions options, - CsvToDicomTagMapping map) - { - _logger.Info("Starting directory scan of " + options.DirectoryToProcessInfo.FullName); - - var dirStack = new Stack(); - dirStack.Push(options.DirectoryToProcessInfo); - - while (dirStack.Count > 0) - { - DirectoryInfo dir = dirStack.Pop(); - _logger.Info("Processing directory " + dir.FullName); - - if (!dir.Exists) - throw new ApplicationException("A previously seen directory can no longer be found: " + dir); - - /*Parallel.ForEach( - dir.EnumerateFiles("*.dcm"), - _parallelOptions, - currentFile => ProcessDicomFile(currentFile, keyDicomTagToColumnIndexMapping, replacementDict, options));*/ - - DirectoryInfo[] subDirs = dir.GetDirectories(); - for (int i = subDirs.Length - 1; i >= 0; i--) - { - _logger.Debug("Found subdirectory " + subDirs[i].FullName); - dirStack.Push(subDirs[i]); + Interlocked.Increment(ref _nDone); - string relativeDir = subDirs[i].FullName.Replace(options.DirectoryToProcessInfo.FullName + Path.DirectorySeparatorChar, ""); - Directory.CreateDirectory(Path.Combine(options.OutputDirectoryInfo.FullName, relativeDir)); - } - } } - /// - /// Processes a single Dicom file applying the required alterations as specified in the replacement dictionary. - /// - /// File to be processed. - /// DicomTag specifying the key and the corresponding column index in the CSV file. - /// Replacement dictionary that maps Series Ids to a Dicom data set that contains new values for the - /// tags to be altered. - /// Command line options. - private void ProcessDicomFile( - FileSystemInfo dFilePath, - Dictionary keyDicomTagToColumnIndexMapping, - Dictionary replacementDict, - DicomRepopulatorOptions options) + public void Dispose() { - _logger.Debug("Processing file " + dFilePath.FullName); - - Interlocked.Increment(ref _nInput); - - DicomFile dFile = DicomFile.Open(dFilePath.FullName); - string inputRelativePath = dFilePath.FullName.Replace(options.DirectoryToProcessInfo.FullName, "").TrimStart(Path.DirectorySeparatorChar); - - string key; - - try - { - DicomTag keyDicomTag = keyDicomTagToColumnIndexMapping.Keys.First(); - string keyTagName = keyDicomTag.DictionaryEntry.Keyword; - - key = dFile.Dataset.GetValue(keyDicomTag, 0); - - if (!replacementDict.ContainsKey(key)) - { - _logger.Warn("No replacement data loaded for file " + inputRelativePath + " with " + keyTagName + "=" + key); - return; - } - - _logger.Debug("Matched file " + keyTagName + "=" + key + " with row from csv data"); - Interlocked.Increment(ref _nMatched); - } - catch (DicomDataException e) - { - _logger.Error("Exception reading data from file " + inputRelativePath + e.Message); - return; - } - - _logger.Debug("Updating file dataset"); - dFile.Dataset.AddOrUpdate(replacementDict[key]); - - _logger.Debug("Saving output file"); - - // Preserves any sub-directory structures - dFile.Save(Path.Combine(options.OutputDirectoryInfo.FullName, inputRelativePath)); - - Interlocked.Increment(ref _nProcessed); + LogManager.Configuration.RemoveTarget(MemoryLogTarget.Name); + MemoryLogTarget?.Dispose(); } } } diff --git a/Repopulator/Matchers/IRepopulatorMatcher.cs b/Repopulator/Matchers/IRepopulatorMatcher.cs index edf0ea3..c6d4488 100644 --- a/Repopulator/Matchers/IRepopulatorMatcher.cs +++ b/Repopulator/Matchers/IRepopulatorMatcher.cs @@ -11,5 +11,7 @@ public interface IRepopulatorMatcher /// null if there are no more files/rows to process /// RepopulatorJob Next(); + + int GetInputFileCount(); } } \ No newline at end of file diff --git a/Repopulator/Matchers/RepopulatorMatcher.cs b/Repopulator/Matchers/RepopulatorMatcher.cs index 12633ef..b00ed15 100644 --- a/Repopulator/Matchers/RepopulatorMatcher.cs +++ b/Repopulator/Matchers/RepopulatorMatcher.cs @@ -1,4 +1,7 @@ using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; namespace Repopulator.Matchers { @@ -16,9 +19,22 @@ public RepopulatorMatcher(CsvToDicomTagMapping map, DicomRepopulatorOptions opti if(string.IsNullOrWhiteSpace(options.InputFolder)) throw new ArgumentException("InputFolder has not been set"); + + } + + protected IEnumerable GetFileList() + { + return Directory.GetFiles(Options.InputFolder, Options.Pattern, + Options.IncludeSubdirectories? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly); } public abstract RepopulatorJob Next(); + + public virtual int GetInputFileCount() + { + return GetFileList().Count(); + } + public abstract void Dispose(); } } \ No newline at end of file diff --git a/Repopulator/Matchers/TagMatcher.cs b/Repopulator/Matchers/TagMatcher.cs index 3327b20..08fdcc3 100644 --- a/Repopulator/Matchers/TagMatcher.cs +++ b/Repopulator/Matchers/TagMatcher.cs @@ -26,9 +26,8 @@ internal class TagMatcher : RepopulatorMatcher public TagMatcher(CsvToDicomTagMapping map, DicomRepopulatorOptions options):base(map,options) { - _fileList = Directory.GetFiles(options.InputFolder, options.Pattern, - options.IncludeSubdirectories? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly); - + _fileList = GetFileList().ToArray(); + _indexer = GetBestIndexer(map); if(_indexer == null) @@ -92,6 +91,11 @@ public override RepopulatorJob Next() } } + public override int GetInputFileCount() + { + return _fileList.Length; + } + public override void Dispose() { diff --git a/TemplateBuilder/Form1.cs b/TemplateBuilder/Form1.cs index 7f80997..35b6d63 100644 --- a/TemplateBuilder/Form1.cs +++ b/TemplateBuilder/Form1.cs @@ -446,10 +446,11 @@ private void tagPopulatorToolStripMenuItem_Click(object sender, EventArgs e) var ui = new RepopulatorUI(); var dc = new DockContent(); + dc.Height = ui.MinimumSize.Height; ui.Dock = DockStyle.Fill; dc.Controls.Add(ui); dc.TabText = "Repopulator"; - dc.Show(dockPanel1,DockState.DockTop); + dc.Show(dockPanel1,DockState.Document); } } diff --git a/TemplateBuilder/RepopulatorUI.Designer.cs b/TemplateBuilder/RepopulatorUI.Designer.cs index ab098b8..812494e 100644 --- a/TemplateBuilder/RepopulatorUI.Designer.cs +++ b/TemplateBuilder/RepopulatorUI.Designer.cs @@ -29,43 +29,49 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(RepopulatorUI)); this.btnInputFolder = new System.Windows.Forms.Button(); this.btnOutputFolder = new System.Windows.Forms.Button(); this.cbIncludeSubfolders = new System.Windows.Forms.CheckBox(); - this.tbPattern = new System.Windows.Forms.TextBox(); + this.tbFilePattern = new System.Windows.Forms.TextBox(); this.tbInputFolder = new System.Windows.Forms.TextBox(); - this.label1 = new System.Windows.Forms.Label(); - this.label3 = new System.Windows.Forms.Label(); + this.lblInputFolder = new System.Windows.Forms.Label(); + this.lblOutputFolder = new System.Windows.Forms.Label(); this.tbOutputFolder = new System.Windows.Forms.TextBox(); - this.label2 = new System.Windows.Forms.Label(); + this.lblFilePattern = new System.Windows.Forms.Label(); this.nThreads = new System.Windows.Forms.NumericUpDown(); - this.label4 = new System.Windows.Forms.Label(); + this.lblThreads = new System.Windows.Forms.Label(); this.lblProgress = new System.Windows.Forms.Label(); this.btnStart = new System.Windows.Forms.Button(); this.tbInputCsv = new System.Windows.Forms.TextBox(); - this.label5 = new System.Windows.Forms.Label(); + this.lblInputCsv = new System.Windows.Forms.Label(); this.btnInputCsv = new System.Windows.Forms.Button(); this.btnValidateCsv = new System.Windows.Forms.Button(); - this.label6 = new System.Windows.Forms.Label(); + this.lblFileNameColumn = new System.Windows.Forms.Label(); this.tbFilenameColumn = new System.Windows.Forms.TextBox(); this.cbAnonymise = new System.Windows.Forms.CheckBox(); this.timer1 = new System.Windows.Forms.Timer(this.components); this.panel1 = new System.Windows.Forms.Panel(); this.tbErrors = new System.Windows.Forms.TextBox(); - this.label9 = new System.Windows.Forms.Label(); + this.lblErrors = new System.Windows.Forms.Label(); this.tbDone = new System.Windows.Forms.TextBox(); - this.label7 = new System.Windows.Forms.Label(); + this.lblDone = new System.Windows.Forms.Label(); this.btnExtraMappings = new System.Windows.Forms.Button(); - this.label8 = new System.Windows.Forms.Label(); + this.lblExtraMappings = new System.Windows.Forms.Label(); this.tbExtraMappings = new System.Windows.Forms.TextBox(); + this.progressBar1 = new System.Windows.Forms.ProgressBar(); + this.btnCopyToClipboard = new System.Windows.Forms.Button(); + this.nErrorThreshold = new System.Windows.Forms.NumericUpDown(); + this.lblErrorThreshold = new System.Windows.Forms.Label(); ((System.ComponentModel.ISupportInitialize)(this.nThreads)).BeginInit(); this.panel1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.nErrorThreshold)).BeginInit(); this.SuspendLayout(); // // btnInputFolder // this.btnInputFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnInputFolder.Location = new System.Drawing.Point(671, 28); + this.btnInputFolder.Location = new System.Drawing.Point(673, 1); this.btnInputFolder.Name = "btnInputFolder"; this.btnInputFolder.Size = new System.Drawing.Size(67, 23); this.btnInputFolder.TabIndex = 1; @@ -76,7 +82,7 @@ private void InitializeComponent() // btnOutputFolder // this.btnOutputFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnOutputFolder.Location = new System.Drawing.Point(671, 158); + this.btnOutputFolder.Location = new System.Drawing.Point(673, 131); this.btnOutputFolder.Name = "btnOutputFolder"; this.btnOutputFolder.Size = new System.Drawing.Size(67, 23); this.btnOutputFolder.TabIndex = 10; @@ -89,7 +95,7 @@ private void InitializeComponent() this.cbIncludeSubfolders.AutoSize = true; this.cbIncludeSubfolders.Checked = true; this.cbIncludeSubfolders.CheckState = System.Windows.Forms.CheckState.Checked; - this.cbIncludeSubfolders.Location = new System.Drawing.Point(96, 56); + this.cbIncludeSubfolders.Location = new System.Drawing.Point(98, 29); this.cbIncludeSubfolders.Name = "cbIncludeSubfolders"; this.cbIncludeSubfolders.Size = new System.Drawing.Size(120, 17); this.cbIncludeSubfolders.TabIndex = 2; @@ -97,14 +103,14 @@ private void InitializeComponent() this.cbIncludeSubfolders.UseVisualStyleBackColor = true; this.cbIncludeSubfolders.CheckedChanged += new System.EventHandler(this.cbIncludeSubfolders_CheckedChanged); // - // tbPattern + // tbFilePattern // - this.tbPattern.Location = new System.Drawing.Point(291, 56); - this.tbPattern.Name = "tbPattern"; - this.tbPattern.Size = new System.Drawing.Size(100, 20); - this.tbPattern.TabIndex = 4; - this.tbPattern.Text = "*.dcm"; - this.tbPattern.TextChanged += new System.EventHandler(this.tbPattern_TextChanged); + this.tbFilePattern.Location = new System.Drawing.Point(293, 29); + this.tbFilePattern.Name = "tbFilePattern"; + this.tbFilePattern.Size = new System.Drawing.Size(100, 20); + this.tbFilePattern.TabIndex = 4; + this.tbFilePattern.Text = "*.dcm"; + this.tbFilePattern.TextChanged += new System.EventHandler(this.tbPattern_TextChanged); // // tbInputFolder // @@ -112,29 +118,29 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Right))); this.tbInputFolder.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.Suggest; this.tbInputFolder.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.FileSystem; - this.tbInputFolder.Location = new System.Drawing.Point(88, 30); + this.tbInputFolder.Location = new System.Drawing.Point(90, 3); this.tbInputFolder.Name = "tbInputFolder"; this.tbInputFolder.Size = new System.Drawing.Size(577, 20); this.tbInputFolder.TabIndex = 0; this.tbInputFolder.TextChanged += new System.EventHandler(this.tb_TextChanged); // - // label1 + // lblInputFolder // - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(10, 33); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(66, 13); - this.label1.TabIndex = 4; - this.label1.Text = "Input Folder:"; + this.lblInputFolder.AutoSize = true; + this.lblInputFolder.Location = new System.Drawing.Point(12, 6); + this.lblInputFolder.Name = "lblInputFolder"; + this.lblInputFolder.Size = new System.Drawing.Size(66, 13); + this.lblInputFolder.TabIndex = 4; + this.lblInputFolder.Text = "Input Folder:"; // - // label3 + // lblOutputFolder // - this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(8, 163); - this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(74, 13); - this.label3.TabIndex = 4; - this.label3.Text = "Output Folder:"; + this.lblOutputFolder.AutoSize = true; + this.lblOutputFolder.Location = new System.Drawing.Point(10, 136); + this.lblOutputFolder.Name = "lblOutputFolder"; + this.lblOutputFolder.Size = new System.Drawing.Size(74, 13); + this.lblOutputFolder.TabIndex = 4; + this.lblOutputFolder.Text = "Output Folder:"; // // tbOutputFolder // @@ -142,24 +148,24 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Right))); this.tbOutputFolder.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.Suggest; this.tbOutputFolder.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.FileSystem; - this.tbOutputFolder.Location = new System.Drawing.Point(88, 160); + this.tbOutputFolder.Location = new System.Drawing.Point(90, 133); this.tbOutputFolder.Name = "tbOutputFolder"; this.tbOutputFolder.Size = new System.Drawing.Size(577, 20); this.tbOutputFolder.TabIndex = 9; this.tbOutputFolder.TextChanged += new System.EventHandler(this.tb_TextChanged); // - // label2 + // lblFilePattern // - this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(222, 59); - this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(63, 13); - this.label2.TabIndex = 3; - this.label2.Text = "File Pattern:"; + this.lblFilePattern.AutoSize = true; + this.lblFilePattern.Location = new System.Drawing.Point(224, 32); + this.lblFilePattern.Name = "lblFilePattern"; + this.lblFilePattern.Size = new System.Drawing.Size(63, 13); + this.lblFilePattern.TabIndex = 3; + this.lblFilePattern.Text = "File Pattern:"; // // nThreads // - this.nThreads.Location = new System.Drawing.Point(452, 57); + this.nThreads.Location = new System.Drawing.Point(454, 30); this.nThreads.Maximum = new decimal(new int[] { 10, 0, @@ -171,7 +177,7 @@ private void InitializeComponent() 0, 0}); this.nThreads.Name = "nThreads"; - this.nThreads.Size = new System.Drawing.Size(111, 20); + this.nThreads.Size = new System.Drawing.Size(54, 20); this.nThreads.TabIndex = 6; this.nThreads.Value = new decimal(new int[] { 1, @@ -180,20 +186,20 @@ private void InitializeComponent() 0}); this.nThreads.ValueChanged += new System.EventHandler(this.nThreads_ValueChanged); // - // label4 + // lblThreads // - this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(397, 59); - this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(49, 13); - this.label4.TabIndex = 5; - this.label4.Text = "Threads:"; + this.lblThreads.AutoSize = true; + this.lblThreads.Location = new System.Drawing.Point(399, 32); + this.lblThreads.Name = "lblThreads"; + this.lblThreads.Size = new System.Drawing.Size(49, 13); + this.lblThreads.TabIndex = 5; + this.lblThreads.Text = "Threads:"; // // lblProgress // this.lblProgress.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.lblProgress.AutoSize = true; - this.lblProgress.Location = new System.Drawing.Point(5, 211); + this.lblProgress.Location = new System.Drawing.Point(31, 184); this.lblProgress.Name = "lblProgress"; this.lblProgress.Size = new System.Drawing.Size(58, 13); this.lblProgress.TabIndex = 9; @@ -201,7 +207,7 @@ private void InitializeComponent() // // btnStart // - this.btnStart.Location = new System.Drawing.Point(219, 186); + this.btnStart.Location = new System.Drawing.Point(221, 159); this.btnStart.Name = "btnStart"; this.btnStart.Size = new System.Drawing.Size(67, 23); this.btnStart.TabIndex = 11; @@ -215,25 +221,25 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Right))); this.tbInputCsv.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.Suggest; this.tbInputCsv.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.FileSystem; - this.tbInputCsv.Location = new System.Drawing.Point(88, 105); + this.tbInputCsv.Location = new System.Drawing.Point(90, 78); this.tbInputCsv.Name = "tbInputCsv"; this.tbInputCsv.Size = new System.Drawing.Size(577, 20); this.tbInputCsv.TabIndex = 7; this.tbInputCsv.TextChanged += new System.EventHandler(this.tb_TextChanged); // - // label5 + // lblInputCsv // - this.label5.AutoSize = true; - this.label5.Location = new System.Drawing.Point(10, 108); - this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(55, 13); - this.label5.TabIndex = 4; - this.label5.Text = "Input Csv:"; + this.lblInputCsv.AutoSize = true; + this.lblInputCsv.Location = new System.Drawing.Point(12, 81); + this.lblInputCsv.Name = "lblInputCsv"; + this.lblInputCsv.Size = new System.Drawing.Size(55, 13); + this.lblInputCsv.TabIndex = 4; + this.lblInputCsv.Text = "Input Csv:"; // // btnInputCsv // this.btnInputCsv.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnInputCsv.Location = new System.Drawing.Point(671, 103); + this.btnInputCsv.Location = new System.Drawing.Point(673, 76); this.btnInputCsv.Name = "btnInputCsv"; this.btnInputCsv.Size = new System.Drawing.Size(67, 23); this.btnInputCsv.TabIndex = 8; @@ -243,7 +249,7 @@ private void InitializeComponent() // // btnValidateCsv // - this.btnValidateCsv.Location = new System.Drawing.Point(88, 186); + this.btnValidateCsv.Location = new System.Drawing.Point(90, 159); this.btnValidateCsv.Name = "btnValidateCsv"; this.btnValidateCsv.Size = new System.Drawing.Size(125, 23); this.btnValidateCsv.TabIndex = 11; @@ -251,18 +257,18 @@ private void InitializeComponent() this.btnValidateCsv.UseVisualStyleBackColor = true; this.btnValidateCsv.Click += new System.EventHandler(this.btnValidateCsv_Click); // - // label6 + // lblFileNameColumn // - this.label6.AutoSize = true; - this.label6.Location = new System.Drawing.Point(93, 82); - this.label6.Name = "label6"; - this.label6.Size = new System.Drawing.Size(87, 13); - this.label6.TabIndex = 12; - this.label6.Text = "Filename Column"; + this.lblFileNameColumn.AutoSize = true; + this.lblFileNameColumn.Location = new System.Drawing.Point(95, 55); + this.lblFileNameColumn.Name = "lblFileNameColumn"; + this.lblFileNameColumn.Size = new System.Drawing.Size(87, 13); + this.lblFileNameColumn.TabIndex = 12; + this.lblFileNameColumn.Text = "Filename Column"; // // tbFilenameColumn // - this.tbFilenameColumn.Location = new System.Drawing.Point(186, 79); + this.tbFilenameColumn.Location = new System.Drawing.Point(188, 52); this.tbFilenameColumn.Name = "tbFilenameColumn"; this.tbFilenameColumn.Size = new System.Drawing.Size(205, 20); this.tbFilenameColumn.TabIndex = 4; @@ -271,7 +277,7 @@ private void InitializeComponent() // cbAnonymise // this.cbAnonymise.AutoSize = true; - this.cbAnonymise.Location = new System.Drawing.Point(400, 81); + this.cbAnonymise.Location = new System.Drawing.Point(402, 54); this.cbAnonymise.Name = "cbAnonymise"; this.cbAnonymise.Size = new System.Drawing.Size(207, 17); this.cbAnonymise.TabIndex = 13; @@ -281,19 +287,21 @@ private void InitializeComponent() // // timer1 // + this.timer1.Enabled = true; this.timer1.Tick += new System.EventHandler(this.timer1_Tick); // // panel1 // + this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.panel1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; this.panel1.Controls.Add(this.tbErrors); - this.panel1.Controls.Add(this.label9); + this.panel1.Controls.Add(this.lblErrors); this.panel1.Controls.Add(this.tbDone); - this.panel1.Controls.Add(this.label7); - this.panel1.Dock = System.Windows.Forms.DockStyle.Bottom; - this.panel1.Location = new System.Drawing.Point(0, 227); + this.panel1.Controls.Add(this.lblDone); + this.panel1.Location = new System.Drawing.Point(3, 214); this.panel1.Name = "panel1"; - this.panel1.Size = new System.Drawing.Size(750, 23); + this.panel1.Size = new System.Drawing.Size(744, 23); this.panel1.TabIndex = 14; // // tbErrors @@ -304,14 +312,14 @@ private void InitializeComponent() this.tbErrors.Size = new System.Drawing.Size(166, 20); this.tbErrors.TabIndex = 12; // - // label9 + // lblErrors // - this.label9.AutoSize = true; - this.label9.Location = new System.Drawing.Point(221, 3); - this.label9.Name = "label9"; - this.label9.Size = new System.Drawing.Size(37, 13); - this.label9.TabIndex = 11; - this.label9.Text = "Errors:"; + this.lblErrors.AutoSize = true; + this.lblErrors.Location = new System.Drawing.Point(221, 3); + this.lblErrors.Name = "lblErrors"; + this.lblErrors.Size = new System.Drawing.Size(37, 13); + this.lblErrors.TabIndex = 11; + this.lblErrors.Text = "Errors:"; // // tbDone // @@ -321,19 +329,19 @@ private void InitializeComponent() this.tbDone.Size = new System.Drawing.Size(166, 20); this.tbDone.TabIndex = 10; // - // label7 + // lblDone // - this.label7.AutoSize = true; - this.label7.Location = new System.Drawing.Point(3, 3); - this.label7.Name = "label7"; - this.label7.Size = new System.Drawing.Size(36, 13); - this.label7.TabIndex = 9; - this.label7.Text = "Done:"; + this.lblDone.AutoSize = true; + this.lblDone.Location = new System.Drawing.Point(3, 3); + this.lblDone.Name = "lblDone"; + this.lblDone.Size = new System.Drawing.Size(36, 13); + this.lblDone.TabIndex = 9; + this.lblDone.Text = "Done:"; // // btnExtraMappings // this.btnExtraMappings.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnExtraMappings.Location = new System.Drawing.Point(671, 132); + this.btnExtraMappings.Location = new System.Drawing.Point(673, 105); this.btnExtraMappings.Name = "btnExtraMappings"; this.btnExtraMappings.Size = new System.Drawing.Size(67, 23); this.btnExtraMappings.TabIndex = 17; @@ -341,14 +349,14 @@ private void InitializeComponent() this.btnExtraMappings.UseVisualStyleBackColor = true; this.btnExtraMappings.Click += new System.EventHandler(this.btnBrowse_Click); // - // label8 + // lblExtraMappings // - this.label8.AutoSize = true; - this.label8.Location = new System.Drawing.Point(4, 137); - this.label8.Name = "label8"; - this.label8.Size = new System.Drawing.Size(83, 13); - this.label8.TabIndex = 15; - this.label8.Text = "Extra Mappings:"; + this.lblExtraMappings.AutoSize = true; + this.lblExtraMappings.Location = new System.Drawing.Point(6, 110); + this.lblExtraMappings.Name = "lblExtraMappings"; + this.lblExtraMappings.Size = new System.Drawing.Size(83, 13); + this.lblExtraMappings.TabIndex = 15; + this.lblExtraMappings.Text = "Extra Mappings:"; // // tbExtraMappings // @@ -356,47 +364,105 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Right))); this.tbExtraMappings.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.Suggest; this.tbExtraMappings.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.FileSystem; - this.tbExtraMappings.Location = new System.Drawing.Point(88, 134); + this.tbExtraMappings.Location = new System.Drawing.Point(90, 107); this.tbExtraMappings.Name = "tbExtraMappings"; this.tbExtraMappings.Size = new System.Drawing.Size(577, 20); this.tbExtraMappings.TabIndex = 16; this.tbExtraMappings.TextChanged += new System.EventHandler(this.tb_TextChanged); // + // progressBar1 + // + this.progressBar1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.progressBar1.Location = new System.Drawing.Point(3, 204); + this.progressBar1.Name = "progressBar1"; + this.progressBar1.Size = new System.Drawing.Size(747, 10); + this.progressBar1.TabIndex = 18; + // + // btnCopyToClipboard + // + this.btnCopyToClipboard.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.btnCopyToClipboard.Image = ((System.Drawing.Image)(resources.GetObject("btnCopyToClipboard.Image"))); + this.btnCopyToClipboard.Location = new System.Drawing.Point(3, 177); + this.btnCopyToClipboard.Name = "btnCopyToClipboard"; + this.btnCopyToClipboard.Size = new System.Drawing.Size(25, 24); + this.btnCopyToClipboard.TabIndex = 19; + this.btnCopyToClipboard.UseVisualStyleBackColor = true; + this.btnCopyToClipboard.Click += new System.EventHandler(this.btnCopyToClipboard_Click); + // + // nErrorThreshold + // + this.nErrorThreshold.Location = new System.Drawing.Point(602, 28); + this.nErrorThreshold.Maximum = new decimal(new int[] { + 65000, + 0, + 0, + 0}); + this.nErrorThreshold.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.nErrorThreshold.Name = "nErrorThreshold"; + this.nErrorThreshold.Size = new System.Drawing.Size(86, 20); + this.nErrorThreshold.TabIndex = 21; + this.nErrorThreshold.Value = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.nErrorThreshold.ValueChanged += new System.EventHandler(this.nErrorThreshold_ValueChanged); + // + // lblErrorThreshold + // + this.lblErrorThreshold.AutoSize = true; + this.lblErrorThreshold.Location = new System.Drawing.Point(514, 32); + this.lblErrorThreshold.Name = "lblErrorThreshold"; + this.lblErrorThreshold.Size = new System.Drawing.Size(82, 13); + this.lblErrorThreshold.TabIndex = 20; + this.lblErrorThreshold.Text = "Error Threshold:"; + // // RepopulatorUI // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoScroll = true; + this.Controls.Add(this.nErrorThreshold); + this.Controls.Add(this.lblErrorThreshold); + this.Controls.Add(this.btnCopyToClipboard); + this.Controls.Add(this.progressBar1); this.Controls.Add(this.btnExtraMappings); - this.Controls.Add(this.label8); + this.Controls.Add(this.lblExtraMappings); this.Controls.Add(this.tbExtraMappings); this.Controls.Add(this.panel1); this.Controls.Add(this.cbAnonymise); - this.Controls.Add(this.label6); + this.Controls.Add(this.lblFileNameColumn); this.Controls.Add(this.btnInputCsv); this.Controls.Add(this.lblProgress); this.Controls.Add(this.nThreads); - this.Controls.Add(this.label4); - this.Controls.Add(this.label2); - this.Controls.Add(this.label5); - this.Controls.Add(this.label3); - this.Controls.Add(this.label1); + this.Controls.Add(this.lblThreads); + this.Controls.Add(this.lblFilePattern); + this.Controls.Add(this.lblInputCsv); + this.Controls.Add(this.lblOutputFolder); + this.Controls.Add(this.lblInputFolder); this.Controls.Add(this.tbOutputFolder); this.Controls.Add(this.tbInputCsv); this.Controls.Add(this.tbInputFolder); this.Controls.Add(this.tbFilenameColumn); - this.Controls.Add(this.tbPattern); + this.Controls.Add(this.tbFilePattern); this.Controls.Add(this.cbIncludeSubfolders); this.Controls.Add(this.btnValidateCsv); this.Controls.Add(this.btnStart); this.Controls.Add(this.btnOutputFolder); this.Controls.Add(this.btnInputFolder); - this.MinimumSize = new System.Drawing.Size(750, 250); + this.MinimumSize = new System.Drawing.Size(750, 240); this.Name = "RepopulatorUI"; - this.Size = new System.Drawing.Size(750, 250); + this.Size = new System.Drawing.Size(750, 240); this.Load += new System.EventHandler(this.RepopulatorUI_Load); ((System.ComponentModel.ISupportInitialize)(this.nThreads)).EndInit(); this.panel1.ResumeLayout(false); this.panel1.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.nErrorThreshold)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -407,31 +473,35 @@ private void InitializeComponent() private System.Windows.Forms.Button btnInputFolder; private System.Windows.Forms.Button btnOutputFolder; private System.Windows.Forms.CheckBox cbIncludeSubfolders; - private System.Windows.Forms.TextBox tbPattern; + private System.Windows.Forms.TextBox tbFilePattern; private System.Windows.Forms.TextBox tbInputFolder; - private System.Windows.Forms.Label label1; - private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label lblInputFolder; + private System.Windows.Forms.Label lblOutputFolder; private System.Windows.Forms.TextBox tbOutputFolder; - private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label lblFilePattern; private System.Windows.Forms.NumericUpDown nThreads; - private System.Windows.Forms.Label label4; + private System.Windows.Forms.Label lblThreads; private System.Windows.Forms.Label lblProgress; private System.Windows.Forms.Button btnStart; private System.Windows.Forms.TextBox tbInputCsv; - private System.Windows.Forms.Label label5; + private System.Windows.Forms.Label lblInputCsv; private System.Windows.Forms.Button btnInputCsv; private System.Windows.Forms.Button btnValidateCsv; - private System.Windows.Forms.Label label6; + private System.Windows.Forms.Label lblFileNameColumn; private System.Windows.Forms.TextBox tbFilenameColumn; private System.Windows.Forms.CheckBox cbAnonymise; private System.Windows.Forms.Timer timer1; private System.Windows.Forms.Panel panel1; private System.Windows.Forms.TextBox tbDone; - private System.Windows.Forms.Label label7; + private System.Windows.Forms.Label lblDone; private System.Windows.Forms.Button btnExtraMappings; - private System.Windows.Forms.Label label8; + private System.Windows.Forms.Label lblExtraMappings; private System.Windows.Forms.TextBox tbExtraMappings; private System.Windows.Forms.TextBox tbErrors; - private System.Windows.Forms.Label label9; + private System.Windows.Forms.Label lblErrors; + private System.Windows.Forms.ProgressBar progressBar1; + private System.Windows.Forms.Button btnCopyToClipboard; + private System.Windows.Forms.NumericUpDown nErrorThreshold; + private System.Windows.Forms.Label lblErrorThreshold; } } diff --git a/TemplateBuilder/RepopulatorUI.cs b/TemplateBuilder/RepopulatorUI.cs index 92e8b2b..1691066 100644 --- a/TemplateBuilder/RepopulatorUI.cs +++ b/TemplateBuilder/RepopulatorUI.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Linq; +using System.Threading.Tasks; using System.Windows.Forms; using Repopulator; using Repopulator.Matchers; @@ -14,6 +15,29 @@ public partial class RepopulatorUI : UserControl private const string StateFile = "RepopulatorUI.yaml"; public DicomRepopulatorProcessor _populator; + private string HelpErrorThreshold = + "The maximum number of errors in file processing / csv file reading before aborting the process"; + public const string HelpCopyToClipboard = + "Copies the current log to the clipboard"; + public const string HelpFilePattern = + "The search pattern to use to identify dicom files in the input directory, defaults to *.dcm. Set to * if you lack file extensions"; + public const string HelpInputCsv = + "Csv file which contains anonymous values that you want to insert into dicom files. Column headers must match dicom tags or you must provide ExtraMappings"; + public const string HelpExtraMappings = + "Optional, allows you to have non dicom tag headers in your CSV file and still map them to 1+ dicom tags. e.g. \"MyFunkyHeader:SOPInstanceUID\""; + public const string HelpInputFolder = + "Directory containing one or more dicom files. These files can be in subdirectories and do not have to have the extension .dcm (if you edit the Pattern)"; + public const string HelpIncludeSubFolders = + "Check to search subdirectories of the input folder"; + public const string HelpFileNameColumn = + "Optional, if your csv file includes a relative or absolute file path to images enter it here to avoid having to match based on SOP/Series/Study instance UID"; + public const string HelpOutputFolder = + "The folder on disk that anonymised output images should be written to"; + + public const string HelpDone = + "The number of anonymous images succesfully written to the output folder"; + public const string HelpErrors = + "The number of errors occuring during processing. For example this can be an error resolving a CSV line or an error writting a tag / file to disk."; public RepopulatorUI() { @@ -34,7 +58,8 @@ public RepopulatorUI() tbExtraMappings.Text = State.InputExtraMappings; tbOutputFolder.Text = State.OutputFolder; nThreads.Value = Math.Min(Math.Max((decimal) nThreads.Minimum,State.NumThreads),nThreads.Maximum); - tbPattern.Text = State.Pattern; + nErrorThreshold.Value = Math.Min(Math.Max((decimal) nErrorThreshold.Minimum, State.ErrorThreshold),nErrorThreshold.Maximum); + tbFilePattern.Text = State.Pattern; tbFilenameColumn.Text = State.FileNameColumn; cbAnonymise.Checked = State.Anonymise; } @@ -42,8 +67,35 @@ public RepopulatorUI() catch (Exception) { } + + var tt = new ToolTip(); + tt.InitialDelay = 0; + tt.AutoPopDelay = 32767; + tt.ShowAlways = true; + tt.SetToolTip(btnInputFolder,HelpInputFolder); + tt.SetToolTip(lblInputFolder,HelpInputFolder); + + tt.SetToolTip(btnInputCsv,HelpInputCsv); + tt.SetToolTip(lblInputCsv,HelpInputCsv); + + tt.SetToolTip(btnExtraMappings,HelpExtraMappings); + tt.SetToolTip(lblExtraMappings,HelpExtraMappings); + + tt.SetToolTip(cbIncludeSubfolders,HelpIncludeSubFolders); + tt.SetToolTip(lblFileNameColumn,HelpFileNameColumn); + tt.SetToolTip(lblFilePattern,HelpFilePattern); + + tt.SetToolTip(btnOutputFolder,HelpOutputFolder); + tt.SetToolTip(lblOutputFolder,HelpOutputFolder); + tt.SetToolTip(btnCopyToClipboard,HelpCopyToClipboard); + + tt.SetToolTip(lblErrorThreshold,HelpErrorThreshold); + + tt.SetToolTip(lblDone,HelpDone); + tt.SetToolTip(lblErrors,HelpErrors); } + private void btnBrowse_Click(object sender, EventArgs e) { @@ -89,16 +141,28 @@ private void BrowseForFile(TextBox destinationTextBox, string filter) private void btnStart_Click(object sender, EventArgs e) { - try - { - _populator = new DicomRepopulatorProcessor(); - _populator.Process(State); - } - catch (Exception exception) + btnStart.Enabled = false; + + var task = new Task(() + => + { using(_populator = new DicomRepopulatorProcessor()) + _populator.Process(State); + }); + + task.ContinueWith((t) => { - MessageBox.Show(exception.Message, "Failed", MessageBoxButtons.OK, MessageBoxIcon.Error); - } + if(t.IsFaulted) + MessageBox.Show(UnpackException(t.Exception), "Failed", MessageBoxButtons.OK, MessageBoxIcon.Error); + + btnStart.Enabled = true; + }, TaskScheduler.FromCurrentSynchronizationContext()); + task.Start(); + } + + private string UnpackException(AggregateException exception) + { + return string.Join(Environment.NewLine,exception.InnerExceptions.Select(e=>e.Message)); } private void tb_TextChanged(object sender, EventArgs e) @@ -139,7 +203,7 @@ private void cbIncludeSubfolders_CheckedChanged(object sender, EventArgs e) private void tbPattern_TextChanged(object sender, EventArgs e) { - State.Pattern = tbPattern.Text; + State.Pattern = tbFilePattern.Text; SaveState(); } @@ -148,6 +212,12 @@ private void nThreads_ValueChanged(object sender, EventArgs e) State.NumThreads = (int) nThreads.Value; SaveState(); } + + private void nErrorThreshold_ValueChanged(object sender, EventArgs e) + { + State.ErrorThreshold = (int) nErrorThreshold.Value; + SaveState(); + } private void btnValidateCsv_Click(object sender, EventArgs e) { @@ -171,25 +241,61 @@ private void cbAnonymise_CheckedChanged(object sender, EventArgs e) private void timer1_Tick(object sender, EventArgs e) { - string log = _populator?.MemoryLogTarget?.Logs?.Last(); + try + { + string log = _populator?.MemoryLogTarget?.Logs?.Last(); + + if (log != lblProgress.Text) + lblProgress.Text = log; + + btnCopyToClipboard.Enabled = log != null; + + int nDone = (_populator?.Done ?? 0); + int nErrors = (_populator?.Errors ?? 0); + int nInput = (_populator?.Input ?? 0); - if (log != lblProgress.Text) - lblProgress.Text = log; + string done = string.Format("{0:n0}",nDone); - string done = (_populator?.Done ?? 0).ToString("{0:n0}"); + if(done != tbDone.Text) + tbDone.Text = done; - if(done != tbDone.Text) - tbDone.Text = done; + string errors = string.Format("{0:n0}",nErrors); - string errors = (_populator?.Errors ?? 0).ToString("{0:n0}"); + if(done != tbErrors.Text) + tbErrors.Text = errors; + + int processed = nDone + nErrors; + + progressBar1.Style = ProgressBarStyle.Continuous; - if(done != tbDone.Text) - tbDone.Text = done; + if (nInput > 0) + { + progressBar1.Maximum = nInput; + progressBar1.Value = Math.Min(processed,nInput); + } + + + } + catch (Exception) + { + tbDone.Text = "-"; + tbErrors.Text = "-"; + lblProgress.Text = "-"; + progressBar1.Style = ProgressBarStyle.Marquee; + } } private void RepopulatorUI_Load(object sender, EventArgs e) { + + } + private void btnCopyToClipboard_Click(object sender, EventArgs e) + { + var logs = _populator?.MemoryLogTarget?.Logs; + if (logs != null) + Clipboard.SetText(string.Join(Environment.NewLine, logs)); } + } } diff --git a/TemplateBuilder/RepopulatorUI.resx b/TemplateBuilder/RepopulatorUI.resx index 1f666f2..3e12e05 100644 --- a/TemplateBuilder/RepopulatorUI.resx +++ b/TemplateBuilder/RepopulatorUI.resx @@ -120,4 +120,22 @@ 17, 17 + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + wwAADsMBx2+oZAAAAoNJREFUOE+dkclPU0EcxzE20Xj0aKKJN71p4oGD+hJNGm6eDIkxEklEotFyICYK + kU3C0lIKqUCxLAVb6EYLrxuvm62lIKXsKC2t3SgFgvof9Ot7U1Os1Yu/5JOZZOb7md/MlPyqE8/KSk5V + UCWn+wbeGj94XFmHk8kydlvWNmvJmi00oVfaTXN7uL1cBkAuPfrqFji0sjoI37wAGwYbhtlKY3pmCjq9 + BmrtBNoaazDRK4BF+gCe12fZ/G+CRe80vv/4hmQqgQ6RCKJuMYRiETsXok3YgZa2VkS+7mD/II2PNkWx + IOi3YicSQk+vGBJCVx7jjB57mRTSe0mk0nHMuzTFgoDPhKOjQxwe7hMODjLsaRlk9vewm04iFo+wY4Lg + d6j/cgWPEZFoGO+GZP9kO7RFBHP2CSLIpdniBAtuHWmxRnUTj0auYnNrDRubOdY3VtkOovkr+Jj3xQK/ + Y5J9pDCqx0rRRN9D+cAlGIz6PMGVADk9tRuH1zZ2LBAob+D5eCmqFddQOXwF9Ya70AR6UKu9A77kHFxu + O5wEBj6/B4lUDB7LyLHgQt1JGJf7oA9KSXAyIIHEUQvFfCeqlXyUtp9hJQ7CnN+LeDIKt0leKODCYkaA + DttTtFqq0Eg/RLP5MQa8Lbg/eh2Xm3jQTamxsraEWCIC14ysUKBelEC50AWFvxPDc+2s5An6vc2oUpaB + W19PLmMp+Anb4S1E42E4jP2Fgj/p8zSicpxP5kMjgywyDMr7MU0byDtMyuqPBVxxvzCrkyAc/UJCFYrb + ZAztfEYonGN9cxVenxtWgxxMw8ViAd1TDqdVle/CaVMVwJjGoZC+hL3hPAnnBRRF8TjB/0BRFO8nJ2GI + ktO5wioAAAAASUVORK5CYII= + + \ No newline at end of file diff --git a/Tests/DicomRepopulatorTests.cs b/Tests/DicomRepopulatorTests.cs index 0bf5659..70fc3df 100644 --- a/Tests/DicomRepopulatorTests.cs +++ b/Tests/DicomRepopulatorTests.cs @@ -63,8 +63,9 @@ public void SingleFileBasicOperationTest() Assert.AreEqual("NewPatientID1", file.Dataset.GetValue(DicomTag.PatientID, 0)); } - [Test] - public void KeyNotFirstColumn() + [TestCase(true)] + [TestCase(false)] + public void KeyNotFirstColumn(bool runSecondaryAnon) { string inputDirPath = Path.Combine(_inputFileBase, "KeyNotFirstColumn"); const string testFileName = IM_0001_0013_NAME; @@ -80,6 +81,7 @@ public void KeyNotFirstColumn() InputCsv = Path.Combine(TestContext.CurrentContext.TestDirectory, "KeyNotFirstColumn.csv"), InputFolder = inputDirPath, OutputFolder = outputDirPath, + Anonymise = runSecondaryAnon, InputExtraMappings = GenerateExtraMappingsFile( "ID:PatientID","sopid:SOPInstanceUID" ), NumThreads = 4 }; From 73f0b564fd39af7f0f754628b6e6d1b911dbe421 Mon Sep 17 00:00:00 2001 From: Thomas Nind Date: Tue, 29 Oct 2019 09:40:20 +0000 Subject: [PATCH 09/19] MSS-58 Added default values when blank text boxes are run. Fixed Error count --- Repopulator/DicomRepopulator.cd | 91 +++++++++++++++++-------- Repopulator/DicomRepopulatorOptions.cs | 8 ++- Repopulator/Matchers/FilePathMatcher.cs | 2 + TemplateBuilder/RepopulatorUI.cs | 6 +- TemplateBuilder/TemplateBuilder.csproj | 2 + 5 files changed, 74 insertions(+), 35 deletions(-) diff --git a/Repopulator/DicomRepopulator.cd b/Repopulator/DicomRepopulator.cd index d59452f..15dc160 100644 --- a/Repopulator/DicomRepopulator.cd +++ b/Repopulator/DicomRepopulator.cd @@ -1,53 +1,84 @@  - - + + - AAAAAQgABAAAAAAAQAECAAQQAAAAAAAEAQAAAAACAAA= - Repopulator\RepopulatorUIState.cs + AgAAAAAAACAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAA= + Matchers\FilePathMatcher.cs - - - - - - - - + + - AAAAAAGAAAAAAAAAAAAAAABAAAAAAAAABAAAAARAAAA= - Repopulator\CsvToDicomTagMapping.cs + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAA= + Matchers\MatcherFactory.cs + + + + + + AgAAAAAAADIAAAAAAAAAAAAAAAAAAAAAIAAAAABAAAA= + Matchers\RepopulatorMatcher.cs + + + + + + + AgAAEAAAACAAAAABAAAAAgAAAAAAAAAAJAQgBAAAAAA= + Matchers\TagMatcher.cs + + + + + + AAAAAAAAAAAAAAAAAgAAAAQAAAAAAAAAAAEAABAAAAA= + CsvToDicomColumn.cs + + + + + + AAACAAGAAAAAAAAAAAAAAABAAAAAAAAABAAAAARBAAA= + CsvToDicomTagMapping.cs - - - - - + + - AAAAAAAAAAAAAAAAAAAAAAQAEAAAAAAAAAEAABAAAAA= - Repopulator\CsvToDicomColumn.cs + AAAAgQgABAAAAAAAQAECAAQQCAAAEAgEASAAAAACAAA= + DicomRepopulatorOptions.cs - - + + + + + - AABAAAAIAAAAASAEAhggAIAAIAAABAAAAAAAAAAAgAA= - Repopulator\DicomRepopulatorProcessor.cs + AAhAAAAIACAAQQAAAgAAAIBAMAAABACAAAAQAAAAgAA= + DicomRepopulatorProcessor.cs - + + + + + + + AAAAAAAAABAAAAAAAAIAAAAAAAAEAAAAAAAAAAAAAAA= + RepopulatorJob.cs + - - + + - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAA= - Repopulator\IFindFilesForRows.cs + AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAA= + Matchers\IRepopulatorMatcher.cs diff --git a/Repopulator/DicomRepopulatorOptions.cs b/Repopulator/DicomRepopulatorOptions.cs index 7b79995..bed5fb6 100644 --- a/Repopulator/DicomRepopulatorOptions.cs +++ b/Repopulator/DicomRepopulatorOptions.cs @@ -6,16 +6,20 @@ namespace Repopulator { public class DicomRepopulatorOptions { + public const string DefaultPattern = "*.dcm"; + public const string DefaultFileNameColumn = ImagingTableCreation.RelativeFileArchiveURI; + public string InputFolder; public string InputCsv; public string InputExtraMappings; public string OutputFolder; public int NumThreads; public bool IncludeSubdirectories = true; - public string Pattern = "*.dcm"; - public string FileNameColumn = ImagingTableCreation.RelativeFileArchiveURI; + public string Pattern = DefaultPattern; + public string FileNameColumn = DefaultFileNameColumn; public bool Anonymise; public int ErrorThreshold = 100; + [YamlIgnore] public DirectoryInfo OutputDirectoryInfo => new DirectoryInfo(OutputFolder); diff --git a/Repopulator/Matchers/FilePathMatcher.cs b/Repopulator/Matchers/FilePathMatcher.cs index 77be613..95209d4 100644 --- a/Repopulator/Matchers/FilePathMatcher.cs +++ b/Repopulator/Matchers/FilePathMatcher.cs @@ -16,6 +16,8 @@ public FilePathMatcher(CsvToDicomTagMapping map, DicomRepopulatorOptions options throw new ArgumentException("Map did not contain file name column"); Reader = new CsvReader(map.CsvFile.OpenText()); + Reader.Read(); + Reader.ReadHeader(); Reader.Configuration.TrimOptions = TrimOptions.Trim; } diff --git a/TemplateBuilder/RepopulatorUI.cs b/TemplateBuilder/RepopulatorUI.cs index 1691066..4b97571 100644 --- a/TemplateBuilder/RepopulatorUI.cs +++ b/TemplateBuilder/RepopulatorUI.cs @@ -203,7 +203,7 @@ private void cbIncludeSubfolders_CheckedChanged(object sender, EventArgs e) private void tbPattern_TextChanged(object sender, EventArgs e) { - State.Pattern = tbFilePattern.Text; + State.Pattern = string.IsNullOrWhiteSpace(tbFilePattern.Text) ? DicomRepopulatorOptions.DefaultPattern:tbFilePattern.Text; SaveState(); } @@ -229,7 +229,7 @@ private void btnValidateCsv_Click(object sender, EventArgs e) private void tbFilenameColumn_TextChanged(object sender, EventArgs e) { - State.FileNameColumn = tbFilenameColumn.Text; + State.FileNameColumn = string.IsNullOrWhiteSpace(tbFilenameColumn.Text) ? DicomRepopulatorOptions.DefaultFileNameColumn : tbFilenameColumn.Text; SaveState(); } @@ -261,7 +261,7 @@ private void timer1_Tick(object sender, EventArgs e) string errors = string.Format("{0:n0}",nErrors); - if(done != tbErrors.Text) + if(errors != tbErrors.Text) tbErrors.Text = errors; int processed = nDone + nErrors; diff --git a/TemplateBuilder/TemplateBuilder.csproj b/TemplateBuilder/TemplateBuilder.csproj index 0f1db18..4090d88 100644 --- a/TemplateBuilder/TemplateBuilder.csproj +++ b/TemplateBuilder/TemplateBuilder.csproj @@ -60,7 +60,9 @@ + + From ca80031af81e62c3f7915117c0b28db262632f25 Mon Sep 17 00:00:00 2001 From: Thomas Nind Date: Wed, 30 Oct 2019 08:32:52 +0000 Subject: [PATCH 10/19] MSS-58 Added helper methods to test to ease setup of repopulator --- Tests/DicomRepopulatorTests.cs | 151 +++++++++++++++++++++++++-------- 1 file changed, 115 insertions(+), 36 deletions(-) diff --git a/Tests/DicomRepopulatorTests.cs b/Tests/DicomRepopulatorTests.cs index 70fc3df..b7eda58 100644 --- a/Tests/DicomRepopulatorTests.cs +++ b/Tests/DicomRepopulatorTests.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; using Dicom; using NUnit.Framework; @@ -31,35 +32,45 @@ public void TearDown() if (Directory.Exists(_seriesFilesBase)) Directory.Delete(_seriesFilesBase, true); } - [Test] - public void SingleFileBasicOperationTest() + public void Test_AbsolutePaths_InCsv() { - string inputDirPath = Path.Combine(_inputFileBase, "SingleFileBasicOperationTest"); - const string testFileName = IM_0001_0013_NAME; - - Directory.CreateDirectory(inputDirPath); - File.WriteAllBytes(Path.Combine(inputDirPath, testFileName), TestDicomFiles.IM_0001_0013); - - string outputDirPath = Path.Combine(_outputFileBase, "SingleFileBasicOperationTest"); - string expectedFile = Path.Combine(outputDirPath, testFileName); + //Create a dicom file in the input dir /subdir/IM_0001_0013.dcm + var inputDicom = CreateInputFile(TestDicomFiles.IM_0001_0013, + Path.Combine("subdir", nameof(TestDicomFiles.IM_0001_0013) +".dcm")); - - var options = new DicomRepopulatorOptions - { - InputCsv = Path.Combine(TestContext.CurrentContext.TestDirectory, "BasicTest.csv"), - InputFolder = inputDirPath, - OutputFolder = outputDirPath, - InputExtraMappings = GenerateExtraMappingsFile("ID:PatientID"), - NumThreads = 4 - }; - - int result = new DicomRepopulatorProcessor(TestContext.CurrentContext.TestDirectory).Process(options); - Assert.AreEqual(0, result); + //Create a CSV with the full path to the image + var inputCsv = CreateInputCsvFile( + $@"File,PatientID +{inputDicom.FullName},ABC"); - Assert.True(File.Exists(expectedFile), "Expected output file {0} to exist", expectedFile); - - DicomFile file = DicomFile.Open(expectedFile); + //run repopulator + var outDir = AssertRunsSuccesfully(1,inputCsv,null,inputDicom.Directory.Parent,(o)=>o.FileNameColumn = "File"); + + //anonymous image should appear in the subdirectory of the out dir + var expectedOutFile = new FileInfo(Path.Combine(outDir.FullName, "subdir", nameof(TestDicomFiles.IM_0001_0013) + ".dcm")); + FileAssert.Exists(expectedOutFile); + } + + [Test] + public void SingleFileBasicOperationTest() + { + var inFile = CreateInputFile(TestDicomFiles.IM_0001_0013,nameof(TestDicomFiles.IM_0001_0013) +".dcm"); + + var outDir = AssertRunsSuccesfully(1, null, + + //Treat Csv column "ID" as a replacement for PatientID + CreateExtraMappingsFile("ID:PatientID"), inFile.Directory, + + //Give it BasicTest.csv + (o) => o.InputCsv= Path.Combine(TestContext.CurrentContext.TestDirectory, "BasicTest.csv")); + + //Anonymous dicom image should exist + var expectedFile = new FileInfo(Path.Combine(outDir.FullName, nameof(TestDicomFiles.IM_0001_0013) + ".dcm")); + FileAssert.Exists(expectedFile); + + //it should have the patient ID from the csv + DicomFile file = DicomFile.Open(expectedFile.FullName); Assert.AreEqual("NewPatientID1", file.Dataset.GetValue(DicomTag.PatientID, 0)); } @@ -82,7 +93,7 @@ public void KeyNotFirstColumn(bool runSecondaryAnon) InputFolder = inputDirPath, OutputFolder = outputDirPath, Anonymise = runSecondaryAnon, - InputExtraMappings = GenerateExtraMappingsFile( "ID:PatientID","sopid:SOPInstanceUID" ), + InputExtraMappings = CreateExtraMappingsFile( "ID:PatientID","sopid:SOPInstanceUID" ).FullName, NumThreads = 4 }; @@ -112,7 +123,7 @@ public void DateRepopulation() InputCsv = Path.Combine(TestContext.CurrentContext.TestDirectory, "WithDate.csv"), InputFolder = inputDirPath, OutputFolder = outputDirPath, - InputExtraMappings = GenerateExtraMappingsFile( "ID:PatientID", "Date:StudyDate" ), + InputExtraMappings = CreateExtraMappingsFile( "ID:PatientID", "Date:StudyDate" ).FullName, NumThreads = 4 }; @@ -144,7 +155,7 @@ public void OneCsvColumnToMultipleDicomTags() InputCsv = Path.Combine(TestContext.CurrentContext.TestDirectory, "WithDate.csv"), InputFolder = inputDirPath, OutputFolder = outputDirPath, - InputExtraMappings = GenerateExtraMappingsFile( "ID:PatientID", "Date:StudyDate", "Date:SeriesDate" ), + InputExtraMappings = CreateExtraMappingsFile( "ID:PatientID", "Date:StudyDate", "Date:SeriesDate" ).FullName, NumThreads = 1 }; @@ -176,7 +187,7 @@ public void SpacesInCsvHeaderTest() InputCsv = Path.Combine(TestContext.CurrentContext.TestDirectory, "SpacesInCsvHeaderTest.csv"), InputFolder = inputDirPath, OutputFolder = outputDirPath, - InputExtraMappings = GenerateExtraMappingsFile( "ID:PatientID" ), + InputExtraMappings = CreateExtraMappingsFile( "ID:PatientID" ).FullName, NumThreads = 1 }; @@ -209,7 +220,7 @@ public void MultipleFilesSameSeriesTest() InputCsv = Path.Combine(TestContext.CurrentContext.TestDirectory, "BasicTest.csv"), InputFolder = inputDirPath, OutputFolder = outputDirPath, - InputExtraMappings = GenerateExtraMappingsFile( "ID:PatientID" ), + InputExtraMappings = CreateExtraMappingsFile( "ID:PatientID" ).FullName, NumThreads = 1 }; @@ -251,7 +262,7 @@ public void MultipleSeriesTest() InputCsv = Path.Combine(TestContext.CurrentContext.TestDirectory, "TwoSeriesCsv.csv"), InputFolder = inputDirPath, OutputFolder = outputDirPath, - InputExtraMappings = GenerateExtraMappingsFile( "ID:PatientID" ), + InputExtraMappings = CreateExtraMappingsFile( "ID:PatientID" ).FullName, NumThreads = 4 }; @@ -276,16 +287,84 @@ public void MultipleSeriesTest() Assert.AreEqual("NewPatientID2", file.Dataset.GetValue(DicomTag.PatientID, 0)); } /// - /// Writes the supplied string to "ExtraMappings.csv" in the test directory and returns the path to the file + /// Writes the supplied string to "ExtraMappings.txt" in the test directory and returns the path to the file /// /// /// - private string GenerateExtraMappingsFile(params string[] contents) + private FileInfo CreateExtraMappingsFile(params string[] contents) { - var filePath = Path.Combine(TestContext.CurrentContext.TestDirectory,"ExtraMappings.csv"); + return GenerateTextFile(contents, "ExtraMappings.txt"); + } + + /// + /// Writes the supplied string to "Map.csv" in the test directory and returns the path to the file + /// + private FileInfo CreateInputCsvFile(params string[] contents) + { + return GenerateTextFile(contents, "Map.csv"); + } + + private FileInfo GenerateTextFile(string[] contents, string filename) + { + var filePath = Path.Combine(TestContext.CurrentContext.TestDirectory,filename); File.WriteAllLines(filePath,contents); - return filePath; + return new FileInfo(filePath); + } + + private FileInfo CreateInputFile(byte[] bytes,string filename,[System.Runtime.CompilerServices.CallerMemberName] string memberName = "") + { + string inputDirPath = Path.Combine(_inputFileBase, memberName); + + Directory.CreateDirectory(inputDirPath); + var toReturn = new FileInfo(Path.Combine(inputDirPath, filename)); + + toReturn.Directory.Create(); + + File.WriteAllBytes(toReturn.FullName, bytes); + + return toReturn; + } + /// + /// Runs the with the provided etc. Asserts that there + /// are no errors during the run and th + /// + /// + /// + /// + /// + /// + /// + private DirectoryInfo AssertRunsSuccesfully(int expectedDone, FileInfo inputCsv, FileInfo inputExtraMapping, + DirectoryInfo inputDicomDirectory, + Action adjustOptions = null, + [System.Runtime.CompilerServices.CallerMemberName] + string memberName = "") + { + string outputDirPath = Path.Combine(_outputFileBase, memberName); + + Directory.CreateDirectory(outputDirPath); + Directory.Delete(outputDirPath,true); + + var options = new DicomRepopulatorOptions + { + InputCsv = inputCsv?.FullName, + InputFolder = inputDicomDirectory?.FullName, + InputExtraMappings = inputExtraMapping?.FullName, + OutputFolder = outputDirPath, + NumThreads = 4 + }; + + adjustOptions?.Invoke(options); + + var processor = new DicomRepopulatorProcessor(TestContext.CurrentContext.TestDirectory); + int result = processor.Process(options); + Assert.AreEqual(0, result); + + Assert.AreEqual(expectedDone,processor.Done); + Assert.AreEqual(0,processor.Errors,"There were non fatal errors, examine processor.MemoryLogTarget for details"); + + return new DirectoryInfo(outputDirPath); } } } From bfd3a5e116a5cdaf34d834559d2d87ebfb5cbc31 Mon Sep 17 00:00:00 2001 From: Thomas Nind Date: Wed, 30 Oct 2019 13:10:01 +0000 Subject: [PATCH 11/19] MSS-58 Documentation, culture awareness and value parsing options (ITagUpdater). --- Repopulator/CsvToDicomTagMapping.cs | 4 +- Repopulator/DicomRepopulator.cd | 35 ++++- Repopulator/DicomRepopulator.md | 76 +++++++++- Repopulator/DicomRepopulatorOptions.cs | 4 +- Repopulator/DicomRepopulatorProcessor.cs | 67 +++++---- Repopulator/Matchers/IRepopulatorMatcher.cs | 6 +- Repopulator/Matchers/RepopulatorMatcher.cs | 2 +- Repopulator/TagUpdaters/ITagUpdater.cs | 15 ++ .../TagUpdaters/ParseStringsUpdater.cs | 74 ++++++++++ TemplateBuilder/RepopulatorUI.Designer.cs | 23 +++ TemplateBuilder/RepopulatorUI.cs | 23 +++ Tests/DicomRepopulatorTests.cs | 138 +++++++++++++++--- 12 files changed, 405 insertions(+), 62 deletions(-) create mode 100644 Repopulator/TagUpdaters/ITagUpdater.cs create mode 100644 Repopulator/TagUpdaters/ParseStringsUpdater.cs diff --git a/Repopulator/CsvToDicomTagMapping.cs b/Repopulator/CsvToDicomTagMapping.cs index 81003c1..eb8e42f 100644 --- a/Repopulator/CsvToDicomTagMapping.cs +++ b/Repopulator/CsvToDicomTagMapping.cs @@ -111,8 +111,8 @@ public bool BuildMap(DicomRepopulatorOptions options, out string log) IsBuilt = true; var matcherFactory = new MatcherFactory(); - matcher = matcherFactory.Create(this,options); - sb.AppendLine($"Matching Strategy is: { matcher?.ToString() ?? "No Strategy Found"}"); + using(matcher = matcherFactory.Create(this,options)) + sb.AppendLine($"Matching Strategy is: { matcher?.ToString() ?? "No Strategy Found"}"); } catch (Exception e) { diff --git a/Repopulator/DicomRepopulator.cd b/Repopulator/DicomRepopulator.cd index 15dc160..6de9266 100644 --- a/Repopulator/DicomRepopulator.cd +++ b/Repopulator/DicomRepopulator.cd @@ -8,7 +8,7 @@ - + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAA= Matchers\MatcherFactory.cs @@ -20,6 +20,9 @@ AgAAAAAAADIAAAAAAAAAAAAAAAAAAAAAIAAAAABAAAA= Matchers\RepopulatorMatcher.cs + + + @@ -28,16 +31,25 @@ AgAAEAAAACAAAAABAAAAAgAAAAAAAAAAJAQgBAAAAAA= Matchers\TagMatcher.cs + + + - - + + AAAAAAAAAAAAAAAAAgAAAAQAAAAAAAAAAAEAABAAAAA= CsvToDicomColumn.cs - + + + + + + + AAACAAGAAAAAAAAAAAAAAABAAAAAAAAABAAAAARBAAA= CsvToDicomTagMapping.cs @@ -45,16 +57,22 @@ + + + - + + + + AAAAgQgABAAAAAAAQAECAAQQCAAAEAgEASAAAAACAAA= DicomRepopulatorOptions.cs - + @@ -68,11 +86,14 @@ - + AAAAAAAAABAAAAAAAAIAAAAAAAAEAAAAAAAAAAAAAAA= RepopulatorJob.cs + + + diff --git a/Repopulator/DicomRepopulator.md b/Repopulator/DicomRepopulator.md index ea39820..cbbdd3d 100644 --- a/Repopulator/DicomRepopulator.md +++ b/Repopulator/DicomRepopulator.md @@ -1,8 +1,15 @@ # Dicom Repopulator +## Contents + +- [Background](#background) +- [Matching Rows to Files](#matching-rows-to-files) + - [By File Path](#by-file-path) + - [File Path Formats](#file-path-formats) + ## Background -The role of this component is to overwrite DicomTags in Dicom images with values provided in a CSV file. +The role of this component is to overwrite DicomTags in Dicom images with values provided in a CSV file. Csv data can be at various granularities e.g. 1 row per Study or 1 row per Image. ## Matching Rows to Files @@ -14,3 +21,70 @@ Each row in the CSV is responsible for updating one or more Dicom images. There ### By File Path +You can specify which image to anonymise directly in the CSV by creating a column called `RelativeFileArchiveURI`. For example + +``` +RelativeFileArchiveURI,PatientID,StudyDate +c:\temp\mydicom.dcm,ABC123,20010101 +```` +_Example CSV that would write mydicom.dcm to the output directory with replaced PatientID and StudyDate values_ + + + +#### File Path Formats + +When specifying the file paths (to dicom files) in the anonymisation CSV you can use either relative or absolute. + +|Format|Example| Supported | +|------|-------|------------| +|Absolute Drive|c:\temp\fish.dcm|Yes| +|Absolute Network| \\\\myserver\my.dcm|Yes| +|Absolute Linux|/usr/my.dcm|Yes| +|Relative Linux (dot prefix)|.\temp\fish.dcm|Yes| +|Relative Windows(dot prefix)|./temp/fish.dcm|Yes| +|Relative No Prefix|temp/fish.dcm|No| + +## Arbitrary Column Names (and 1-to-n mapping) + +Normally columns in the CSV are expected to be named after dicom tags e.g. PatientID. However you can use your own headers (e.g. patid) by supplying an `Extra Mappings` file. + +Extra mappings are specified in the following format: + +``` +SomeCsvColumn:DicomTagName +``` + +Extra mappings can be used to populate multiple tags by specifying the same csv column multiple times: + +``` +MyDate:StudyDate +MyDate:SeriesDate +``` +_Example would write values stored in the MyDate column of the CSV into dicom tags StudyDate and SeriesDate_ + + +## Outstanding Issues + +- Sequences + - Populate an entire sequence + - Dive into sequence and populate only a given leaf +- Multiplicity +- CLI version? +- Use case, you want arbitrary file paths in CSV into a large repository of images (millions) and don't want to do the `dir *.dcm recursive` just to get the count of files to process (applies only to `FilePathMatcher`) + +- Null behaviour? What happens when the csv has no value in a cell do we skip the tag or remove it? + +## Error states + +- Csv file path is to a file not in Input Directory (means counts arent accurate) +- File on disk has UID not in CSV +- CSV has UIDs not on disk (warning?) + +- Files do not exist +- Hidden files e.g. thumbs.db especially when processing dicoms that lack extensions (apparently .dcm is optional in dicom format) + +- Two+ rows in CSV with same UID e.g. SeriesInstanceUID when no SOPInstanceUID + +- Overwritting of same file with different answer e.g. CSV file has path in two places in it + + diff --git a/Repopulator/DicomRepopulatorOptions.cs b/Repopulator/DicomRepopulatorOptions.cs index bed5fb6..0e109ed 100644 --- a/Repopulator/DicomRepopulatorOptions.cs +++ b/Repopulator/DicomRepopulatorOptions.cs @@ -1,4 +1,5 @@ -using System.IO; +using System.Globalization; +using System.IO; using DicomTypeTranslation.TableCreation; using YamlDotNet.Serialization; @@ -19,6 +20,7 @@ public class DicomRepopulatorOptions public string FileNameColumn = DefaultFileNameColumn; public bool Anonymise; public int ErrorThreshold = 100; + public CultureInfo Culture = CultureInfo.CurrentCulture; [YamlIgnore] diff --git a/Repopulator/DicomRepopulatorProcessor.cs b/Repopulator/DicomRepopulatorProcessor.cs index 1af72c5..bb3c931 100644 --- a/Repopulator/DicomRepopulatorProcessor.cs +++ b/Repopulator/DicomRepopulatorProcessor.cs @@ -7,11 +7,15 @@ using System.Threading; using System.Threading.Tasks; using Dicom; +using DicomTypeTranslation; using DicomTypeTranslation.Helpers; +using FAnsi.Discovery.QuerySyntax.Update; using NLog; using NLog.Config; using NLog.Targets; using Repopulator.Matchers; +using Repopulator.TagUpdaters; +using TypeGuesser.Deciders; namespace Repopulator { @@ -23,7 +27,9 @@ public class DicomRepopulatorProcessor: IDisposable private ParallelOptions _parallelOptions; private DicomAnonymizer _anonymizer; - + + private ITagUpdater _tagUpdater; + public IRepopulatorMatcher Matcher { get; private set; } public MemoryTarget MemoryLogTarget { get; } = new MemoryTarget(){Name = "DicomRepopulatorProcessor_Memory"}; @@ -61,7 +67,7 @@ public DicomRepopulatorProcessor(string currentDirectory = null) public int Process(DicomRepopulatorOptions options) { _parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = options.NumThreads }; - + _tagUpdater = new ParseStringsUpdater(options.Culture); _anonymizer = options.Anonymise ? new DicomAnonymizer() : null; if(!options.OutputDirectoryInfo.Exists) @@ -97,34 +103,35 @@ public int Process(DicomRepopulatorOptions options) var factory = new MatcherFactory(); - Matcher = factory.Create(map, options); - - if (Matcher == null) - throw new Exception("No suitable IRepopulatorMatcher could be built, ensure you have either file paths or instance UIDs in your csv file / extra mappings (otherwise we have no way to match rows to files)"); + using (Matcher = factory.Create(map, options)) + { + if (Matcher == null) + throw new Exception("No suitable IRepopulatorMatcher could be built, ensure you have either file paths or instance UIDs in your csv file / extra mappings (otherwise we have no way to match rows to files)"); - _nInput = Matcher.GetInputFileCount(); + _nInput = Matcher.GetInputFileCount(); - RepopulatorJob job = null; + RepopulatorJob job = null; - //while there are more jobs - do - { - try + //while there are more jobs + do { - job = Matcher.Next(); + try + { + job = Matcher.Next(); - if(job != null) - ProcessJob(job, options); - } - catch (Exception e) - { - _logger.Error(e); - Interlocked.Increment(ref _nErrors); - } - } while (job != null && _nErrors < options.ErrorThreshold); - - if(_nErrors >= options.ErrorThreshold) - throw new Exception("Error threshold reached"); + if(job != null) + ProcessJob(job, options); + } + catch (Exception e) + { + _logger.Error(e); + Interlocked.Increment(ref _nErrors); + } + } while (job != null && _nErrors < options.ErrorThreshold); + + if(_nErrors >= options.ErrorThreshold) + throw new Exception("Error threshold reached"); + } var sb = new StringBuilder(); sb.AppendLine("\n=== Finished processing ==="); @@ -138,16 +145,16 @@ public int Process(DicomRepopulatorOptions options) return 0; } - + + + private void ProcessJob(RepopulatorJob job, DicomRepopulatorOptions options) { if(options.Anonymise) _anonymizer.AnonymizeInPlace(job.File.Dataset); - foreach (var col in job.Map.TagColumns) - foreach (DicomTag dicomTag in col.TagsToPopulate) - job.File.Dataset.AddOrUpdate(dicomTag, job.Cells[col.Index]); - + _tagUpdater.UpdateTags(job); + //the relative location in the archive var inputRelativePath = job.File.File.Name.Replace(options.DirectoryToProcessInfo.FullName, "").TrimStart(Path.DirectorySeparatorChar); diff --git a/Repopulator/Matchers/IRepopulatorMatcher.cs b/Repopulator/Matchers/IRepopulatorMatcher.cs index c6d4488..a6bc0cf 100644 --- a/Repopulator/Matchers/IRepopulatorMatcher.cs +++ b/Repopulator/Matchers/IRepopulatorMatcher.cs @@ -1,10 +1,12 @@ -namespace Repopulator.Matchers +using System; + +namespace Repopulator.Matchers { /// /// Interface for classes that match Csv rows to files on disk. This could be as simple as following a file URI or as /// complicated as reading a UID returning the corresponding files /// - public interface IRepopulatorMatcher + public interface IRepopulatorMatcher:IDisposable { /// /// Returns the next file to be repopulated and the corresponding values to overwrite with. Returns diff --git a/Repopulator/Matchers/RepopulatorMatcher.cs b/Repopulator/Matchers/RepopulatorMatcher.cs index b00ed15..b34d987 100644 --- a/Repopulator/Matchers/RepopulatorMatcher.cs +++ b/Repopulator/Matchers/RepopulatorMatcher.cs @@ -5,7 +5,7 @@ namespace Repopulator.Matchers { - public abstract class RepopulatorMatcher : IRepopulatorMatcher, IDisposable + public abstract class RepopulatorMatcher : IRepopulatorMatcher { protected DicomRepopulatorOptions Options { get; } protected CsvToDicomTagMapping Map { get; } diff --git a/Repopulator/TagUpdaters/ITagUpdater.cs b/Repopulator/TagUpdaters/ITagUpdater.cs new file mode 100644 index 0000000..f283695 --- /dev/null +++ b/Repopulator/TagUpdaters/ITagUpdater.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Repopulator.TagUpdaters +{ + /// + /// Strategy pattern interface for classes that update in a + /// with raw string values (handles translation from string to dicom types). + /// + interface ITagUpdater + { + void UpdateTags(RepopulatorJob job); + } +} diff --git a/Repopulator/TagUpdaters/ParseStringsUpdater.cs b/Repopulator/TagUpdaters/ParseStringsUpdater.cs new file mode 100644 index 0000000..5ed9515 --- /dev/null +++ b/Repopulator/TagUpdaters/ParseStringsUpdater.cs @@ -0,0 +1,74 @@ +using System.Globalization; +using System.Linq; +using Dicom; +using DicomTypeTranslation; +using TypeGuesser; +using TypeGuesser.Deciders; + +namespace Repopulator.TagUpdaters +{ + public abstract class TagUpdater : ITagUpdater + { + public virtual void UpdateTags(RepopulatorJob job) + { + foreach (var col in job.Map.TagColumns) + foreach (DicomTag dicomTag in col.TagsToPopulate) + UpdateTag(dicomTag, job.File.Dataset, job.Cells[col.Index]); + } + + protected abstract void UpdateTag(DicomTag dicomTag, DicomDataset dataset, string cellValue); + } + + /// + /// Updater which uses FAnsi to translate the string value into the c sharp + /// type (e.g. DateTime) before writing to dicom. Types that do not map to FAnsi or that fail parsing are written + /// as raw string values + /// + class ParseStringsUpdater : TagUpdater + { + private TypeDeciderFactory _factory; + + public ParseStringsUpdater(CultureInfo culture) + { + _factory = new TypeDeciderFactory(culture); + } + + protected override void UpdateTag(DicomTag dicomTag, DicomDataset dataset, string cellValue) + { + var cSharpType = DicomTypeTranslater.GetNaturalTypeForVr(dicomTag.DictionaryEntry.ValueRepresentations, + dicomTag.DictionaryEntry.ValueMultiplicity)?.CSharpType; + + object writeValue = cellValue; + + //if it's a supported type e.g. DateTime parse it + if (cSharpType != null && _factory.IsSupported(cSharpType)) + if (_factory.Dictionary[cSharpType].IsAcceptableAsType(cellValue, Ignore.Me )) + writeValue = _factory.Dictionary[cSharpType].Parse(cellValue); + + dataset.Remove(dicomTag); + DicomTypeTranslaterWriter.SetDicomTag(dataset,dicomTag,writeValue); + } + private class Ignore : IDataTypeSize + { + private static IDataTypeSize _instance = new Ignore(); + + public DecimalSize Size { get; set; } = new DecimalSize(); + public int? Width { get; set; } + public bool Unicode { get; set; } + public static IDataTypeSize Me => _instance; + } + } + + + /// + /// Updater which calls directly with the string value. This + /// can result in successful writes that break on read attempts in downstream components + /// + class NaiveUpdater : TagUpdater + { + protected override void UpdateTag(DicomTag dicomTag, DicomDataset dataset, string cellValue) + { + dataset.AddOrUpdate(dicomTag, cellValue); + } + } +} \ No newline at end of file diff --git a/TemplateBuilder/RepopulatorUI.Designer.cs b/TemplateBuilder/RepopulatorUI.Designer.cs index 812494e..b7f892e 100644 --- a/TemplateBuilder/RepopulatorUI.Designer.cs +++ b/TemplateBuilder/RepopulatorUI.Designer.cs @@ -63,6 +63,8 @@ private void InitializeComponent() this.btnCopyToClipboard = new System.Windows.Forms.Button(); this.nErrorThreshold = new System.Windows.Forms.NumericUpDown(); this.lblErrorThreshold = new System.Windows.Forms.Label(); + this.lblCulture = new System.Windows.Forms.Label(); + this.tbCulture = new System.Windows.Forms.TextBox(); ((System.ComponentModel.ISupportInitialize)(this.nThreads)).BeginInit(); this.panel1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.nErrorThreshold)).BeginInit(); @@ -422,11 +424,30 @@ private void InitializeComponent() this.lblErrorThreshold.TabIndex = 20; this.lblErrorThreshold.Text = "Error Threshold:"; // + // lblCulture + // + this.lblCulture.AutoSize = true; + this.lblCulture.Location = new System.Drawing.Point(522, 165); + this.lblCulture.Name = "lblCulture"; + this.lblCulture.Size = new System.Drawing.Size(43, 13); + this.lblCulture.TabIndex = 22; + this.lblCulture.Text = "Culture:"; + // + // tbCulture + // + this.tbCulture.Location = new System.Drawing.Point(567, 162); + this.tbCulture.Name = "tbCulture"; + this.tbCulture.Size = new System.Drawing.Size(100, 20); + this.tbCulture.TabIndex = 23; + this.tbCulture.TextChanged += new System.EventHandler(this.tbCulture_TextChanged); + // // RepopulatorUI // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScroll = true; + this.Controls.Add(this.tbCulture); + this.Controls.Add(this.lblCulture); this.Controls.Add(this.nErrorThreshold); this.Controls.Add(this.lblErrorThreshold); this.Controls.Add(this.btnCopyToClipboard); @@ -503,5 +524,7 @@ private void InitializeComponent() private System.Windows.Forms.Button btnCopyToClipboard; private System.Windows.Forms.NumericUpDown nErrorThreshold; private System.Windows.Forms.Label lblErrorThreshold; + private System.Windows.Forms.Label lblCulture; + private System.Windows.Forms.TextBox tbCulture; } } diff --git a/TemplateBuilder/RepopulatorUI.cs b/TemplateBuilder/RepopulatorUI.cs index 4b97571..0e9a6f2 100644 --- a/TemplateBuilder/RepopulatorUI.cs +++ b/TemplateBuilder/RepopulatorUI.cs @@ -1,4 +1,6 @@ using System; +using System.Drawing; +using System.Globalization; using System.IO; using System.Linq; using System.Threading.Tasks; @@ -39,6 +41,9 @@ public partial class RepopulatorUI : UserControl public const string HelpErrors = "The number of errors occuring during processing. For example this can be an error resolving a CSV line or an error writting a tag / file to disk."; + public const string HelpCulture + = "The culture to use for parsing string values into dicom types e.g. dates, numbers"; + public RepopulatorUI() { InitializeComponent(); @@ -62,6 +67,7 @@ public RepopulatorUI() tbFilePattern.Text = State.Pattern; tbFilenameColumn.Text = State.FileNameColumn; cbAnonymise.Checked = State.Anonymise; + tbCulture.Text = State.Culture.DisplayName; } } catch (Exception) @@ -94,6 +100,8 @@ public RepopulatorUI() tt.SetToolTip(lblDone,HelpDone); tt.SetToolTip(lblErrors,HelpErrors); + + tt.SetToolTip(lblCulture,HelpCulture); } @@ -297,5 +305,20 @@ private void btnCopyToClipboard_Click(object sender, EventArgs e) Clipboard.SetText(string.Join(Environment.NewLine, logs)); } + private void tbCulture_TextChanged(object sender, EventArgs e) + { + try + { + State.Culture = new CultureInfo(tbCulture.Text); + tbCulture.ForeColor = Color.Black; + } + catch (Exception) + { + tbCulture.ForeColor = Color.Red; + } + + SaveState(); + + } } } diff --git a/Tests/DicomRepopulatorTests.cs b/Tests/DicomRepopulatorTests.cs index b7eda58..4dfcfb4 100644 --- a/Tests/DicomRepopulatorTests.cs +++ b/Tests/DicomRepopulatorTests.cs @@ -33,7 +33,7 @@ public void TearDown() } [Test] - public void Test_AbsolutePaths_InCsv() + public void Test_AbsolutePath_InCsv() { //Create a dicom file in the input dir /subdir/IM_0001_0013.dcm var inputDicom = CreateInputFile(TestDicomFiles.IM_0001_0013, @@ -45,19 +45,90 @@ public void Test_AbsolutePaths_InCsv() {inputDicom.FullName},ABC"); //run repopulator - var outDir = AssertRunsSuccesfully(1,inputCsv,null,inputDicom.Directory.Parent,(o)=>o.FileNameColumn = "File"); + var outDir = AssertRunsSuccesfully(1, + 0, + inputCsv, + null, + inputDicom.Directory.Parent, + (o) => o.FileNameColumn = "File"); //anonymous image should appear in the subdirectory of the out dir var expectedOutFile = new FileInfo(Path.Combine(outDir.FullName, "subdir", nameof(TestDicomFiles.IM_0001_0013) + ".dcm")); FileAssert.Exists(expectedOutFile); } - + + [TestCase("./subdir/IM_0001_0013.dcm")] + [TestCase("subdir/IM_0001_0013.dcm")] + [TestCase("./../Test_RelativePath_InCsv/subdir/IM_0001_0013.dcm")] + public void Test_RelativePath_InCsv(string csvPath) + { + //Create a dicom file in the input dir /subdir/IM_0001_0013.dcm + var inputDicom = CreateInputFile(TestDicomFiles.IM_0001_0013, + Path.Combine("subdir", nameof(TestDicomFiles.IM_0001_0013) +".dcm")); + + //Create a CSV with the full path to the image + var inputCsv = CreateInputCsvFile( + $@"File,PatientID +{csvPath},ABC"); + + //run repopulator + var outDir = AssertRunsSuccesfully(1, + 0, + inputCsv, + null, + inputDicom.Directory.Parent, + (o) => o.FileNameColumn = "File"); + + //anonymous image should appear in the subdirectory of the out dir + var expectedOutFile = new FileInfo(Path.Combine(outDir.FullName, "subdir", nameof(TestDicomFiles.IM_0001_0013) + ".dcm")); + FileAssert.Exists(expectedOutFile); + } + + [Test] + public void Test_StudyDateTag_GoodData() + { + var inputDicom = CreateInputFile(TestDicomFiles.IM_0001_0013, "mydicom.dcm"); + var inputCsv = CreateInputCsvFile( + $@"RelativeFileArchiveURI,PatientID,StudyDate +{inputDicom.FullName},ABC123,2001-01-01"); + + var outDir = AssertRunsSuccesfully(1,0,inputCsv,null,inputDicom.Directory); + + var fi = new FileInfo (Path.Combine(outDir.FullName,"mydicom.dcm")); + FileAssert.Exists(fi); + + DicomFile file = DicomFile.Open(fi.FullName); + Assert.AreEqual("ABC123", file.Dataset.GetValue(DicomTag.PatientID, 0)); + Assert.AreEqual(new DateTime(2001,1,1), file.Dataset.GetValue(DicomTag.StudyDate, 0)); + + } + + [Test] + public void Test_StudyDateTag_BadData() + { + var inputDicom = CreateInputFile(TestDicomFiles.IM_0001_0013, "mydicom.dcm"); + var inputCsv = CreateInputCsvFile( + $@"RelativeFileArchiveURI,PatientID,StudyDate +{inputDicom.FullName},ABC123,Lolz"); + + //should be an error because Lolz is not a valid date! + var outDir = AssertRunsSuccesfully(0,1,inputCsv,null,inputDicom.Directory); + + var fi = new FileInfo (Path.Combine(outDir.FullName,"mydicom.dcm")); + FileAssert.Exists(fi); + + DicomFile file = DicomFile.Open(fi.FullName); + Assert.AreEqual("ABC123", file.Dataset.GetValue(DicomTag.PatientID, 0)); + Assert.AreEqual(new DateTime(2001,1,1), file.Dataset.GetValue(DicomTag.StudyDate, 0)); + + } + [Test] public void SingleFileBasicOperationTest() { var inFile = CreateInputFile(TestDicomFiles.IM_0001_0013,nameof(TestDicomFiles.IM_0001_0013) +".dcm"); - var outDir = AssertRunsSuccesfully(1, null, + var outDir = AssertRunsSuccesfully(1, 0,null, //Treat Csv column "ID" as a replacement for PatientID CreateExtraMappingsFile("ID:PatientID"), inFile.Directory, @@ -312,6 +383,14 @@ private FileInfo GenerateTextFile(string[] contents, string filename) return new FileInfo(filePath); } + /// + /// Creates a new input directory with the name of the calling method (under ) then creates + /// the given dicom file () at location (which can include subdirectories) + /// + /// The dicom files raw bytes + /// The filename to write out e.g. "my.dcm" or "mysubdir/my.dcm" + /// + /// private FileInfo CreateInputFile(byte[] bytes,string filename,[System.Runtime.CompilerServices.CallerMemberName] string memberName = "") { string inputDirPath = Path.Combine(_inputFileBase, memberName); @@ -335,36 +414,59 @@ private FileInfo CreateInputFile(byte[] bytes,string filename,[System.Runtime.Co /// /// /// - private DirectoryInfo AssertRunsSuccesfully(int expectedDone, FileInfo inputCsv, FileInfo inputExtraMapping, + private DirectoryInfo AssertRunsSuccesfully(int expectedDone, int expectedErrors, FileInfo inputCsv, FileInfo inputExtraMapping, DirectoryInfo inputDicomDirectory, Action adjustOptions = null, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "") { - string outputDirPath = Path.Combine(_outputFileBase, memberName); + var processor = GetProcessor(inputCsv, + inputExtraMapping, + inputDicomDirectory, + adjustOptions, + memberName, + out DicomRepopulatorOptions options, + out DirectoryInfo outputDirPath); + + int result = processor.Process(options); + Assert.AreEqual(0, result); + + foreach (var log in processor.MemoryLogTarget.Logs) + Console.WriteLine(log); - Directory.CreateDirectory(outputDirPath); - Directory.Delete(outputDirPath,true); + Assert.AreEqual(expectedErrors,processor.Errors,"Expected error count was not correct"); + Assert.AreEqual(expectedDone,processor.Done, "Expected success count was not correct"); - var options = new DicomRepopulatorOptions + return outputDirPath; + } + + private DicomRepopulatorProcessor GetProcessor(FileInfo inputCsv, FileInfo inputExtraMapping, + DirectoryInfo inputDicomDirectory, Action adjustOptions, string memberName, + out DicomRepopulatorOptions options, + out DirectoryInfo outputDirPath) + { + outputDirPath = new DirectoryInfo(Path.Combine(_outputFileBase, memberName)); + + //delete old content + if(Directory.Exists(outputDirPath.FullName)) + Directory.Delete(outputDirPath.FullName,true); + + Directory.CreateDirectory(outputDirPath.FullName); + + + options = new DicomRepopulatorOptions { InputCsv = inputCsv?.FullName, InputFolder = inputDicomDirectory?.FullName, InputExtraMappings = inputExtraMapping?.FullName, - OutputFolder = outputDirPath, + OutputFolder = outputDirPath.FullName, NumThreads = 4 }; adjustOptions?.Invoke(options); - var processor = new DicomRepopulatorProcessor(TestContext.CurrentContext.TestDirectory); - int result = processor.Process(options); - Assert.AreEqual(0, result); - - Assert.AreEqual(expectedDone,processor.Done); - Assert.AreEqual(0,processor.Errors,"There were non fatal errors, examine processor.MemoryLogTarget for details"); - - return new DirectoryInfo(outputDirPath); + return new DicomRepopulatorProcessor(TestContext.CurrentContext.TestDirectory); } + } } From 24b5e6bd9bd6c549fc6866d2a4c696e4590fb1a0 Mon Sep 17 00:00:00 2001 From: tznind Date: Mon, 9 Dec 2019 09:24:45 +0000 Subject: [PATCH 12/19] Added repopulator documentation --- Repopulator/DicomRepopulator.md | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/Repopulator/DicomRepopulator.md b/Repopulator/DicomRepopulator.md index cbbdd3d..e68f86d 100644 --- a/Repopulator/DicomRepopulator.md +++ b/Repopulator/DicomRepopulator.md @@ -4,8 +4,12 @@ - [Background](#background) - [Matching Rows to Files](#matching-rows-to-files) - - [By File Path](#by-file-path) + - [Match by File Path](#match-by-file-path) - [File Path Formats](#file-path-formats) + - [Match by Tag](#match-by-tag) +- [Extra Column Mappings](#extra-column-mappings) +- [Outstanding Issues](#outstanding-issues) +- [Error States](#error-states) ## Background @@ -19,7 +23,7 @@ Each row in the CSV is responsible for updating one or more Dicom images. There - By SopInstanceUID - By secondary UID (SeriesInstanceUID or StudyInstanceUID) -### By File Path +### Match By File Path You can specify which image to anonymise directly in the CSV by creating a column called `RelativeFileArchiveURI`. For example @@ -44,7 +48,16 @@ When specifying the file paths (to dicom files) in the anonymisation CSV you can |Relative Windows(dot prefix)|./temp/fish.dcm|Yes| |Relative No Prefix|temp/fish.dcm|No| -## Arbitrary Column Names (and 1-to-n mapping) +### Match By Tag + +If file path is a problem then Csv files can instead contain the file(s) UIDs. If there is a column called `SOPInstanceUID` then this will be used to map between CSV and files in the input directory. + +If `SOPInstanceUID` is unavailable then Series / Study UID tags will be used for mapping. This allows you to specify a set of values in the CSV that should be overwritten in all images in a series/study at once. + +When matching on tag the entire CSV has to be read into memory at once (in order to match files as they are found). This may be a problem with very large CSV files. + + +## Extra Column Mappings Normally columns in the CSV are expected to be named after dicom tags e.g. PatientID. However you can use your own headers (e.g. patid) by supplying an `Extra Mappings` file. @@ -62,7 +75,6 @@ MyDate:SeriesDate ``` _Example would write values stored in the MyDate column of the CSV into dicom tags StudyDate and SeriesDate_ - ## Outstanding Issues - Sequences From 826a82a16235cece832898f4191b588cf5e77ca9 Mon Sep 17 00:00:00 2001 From: tznind Date: Mon, 9 Dec 2019 09:26:23 +0000 Subject: [PATCH 13/19] Updated to latest version of FAnsi / DicomTypeTranslation --- Repopulator/Repopulator.csproj | 2 +- TemplateBuilder/TemplateBuilder.csproj | 4 ++-- Tests/Tests.csproj | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Repopulator/Repopulator.csproj b/Repopulator/Repopulator.csproj index df49eeb..527dbd9 100644 --- a/Repopulator/Repopulator.csproj +++ b/Repopulator/Repopulator.csproj @@ -8,7 +8,7 @@ - + diff --git a/TemplateBuilder/TemplateBuilder.csproj b/TemplateBuilder/TemplateBuilder.csproj index 4090d88..632f822 100644 --- a/TemplateBuilder/TemplateBuilder.csproj +++ b/TemplateBuilder/TemplateBuilder.csproj @@ -63,8 +63,8 @@ - - + + diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index f5ae710..783720b 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -13,7 +13,7 @@ - + From 57a0f25e75c28e7f6f59e18c13743c309e5ae0f9 Mon Sep 17 00:00:00 2001 From: tznind Date: Mon, 9 Dec 2019 09:33:27 +0000 Subject: [PATCH 14/19] Added travis build/test --- .travis.yml | 10 ++++++++++ TemplateBuilder.sln | 5 +++-- 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..04bfab8 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,10 @@ +dist: bionic +jobs: + include: + - language: csharp + mono: none + dotnet: 2.2.100 + + script: + - dotnet build --verbosity quiet + - dotnet test ./Tests/Tests.csproj diff --git a/TemplateBuilder.sln b/TemplateBuilder.sln index 1ef6715..fcacc09 100644 --- a/TemplateBuilder.sln +++ b/TemplateBuilder.sln @@ -7,14 +7,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TemplateBuilder", "Template EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{30CD1058-100D-42BE-8C0D-8FC425559D06}" ProjectSection(SolutionItems) = preProject + .travis.yml = .travis.yml rakeconfig.rb = rakeconfig.rb rakefile.rb = rakefile.rb README.md = README.md EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{66EED857-25C6-4FF9-967A-333CB151DF0B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "Tests\Tests.csproj", "{66EED857-25C6-4FF9-967A-333CB151DF0B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Repopulator", "Repopulator\Repopulator.csproj", "{3B0E5AC1-5439-470C-832D-7DE566B22CD8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Repopulator", "Repopulator\Repopulator.csproj", "{3B0E5AC1-5439-470C-832D-7DE566B22CD8}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution From 9a64310c26a34bafbbc3c10028e8cbe7a23e45fa Mon Sep 17 00:00:00 2001 From: tznind Date: Mon, 9 Dec 2019 09:57:00 +0000 Subject: [PATCH 15/19] Added changelog and fixed build for travis --- .travis.yml | 1 - CHANGELOG.md | 21 +++++++++++++++++++++ TemplateBuilder.sln | 1 + TemplateBuilder/TemplateBuilder.csproj | 1 - Tests/DicomRepopulatorTests.cs | 1 + Tests/Tests.csproj | 4 ++-- 6 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 CHANGELOG.md diff --git a/.travis.yml b/.travis.yml index 04bfab8..157c849 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,5 +6,4 @@ jobs: dotnet: 2.2.100 script: - - dotnet build --verbosity quiet - dotnet test ./Tests/Tests.csproj diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..af87010 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,21 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added + +- Added initial iteration of dicom tag repopulator (anonymises dicom images based on CSV data) +- Updated [DicomTypeTranslation] to 2.1.2 + +## [1.0.0] - 2019-10-01 + +Initial version + + +[Unreleased]: https://github.com/HicServices/DicomTemplateBuilder/compare/v1.0.0...develop +[1.0.0]: https://github.com/HicServices/DicomTemplateBuilder/tree/v1.0.0 +[DicomTypeTranslation]: https://github.com/HicServices/DicomTypeTranslation \ No newline at end of file diff --git a/TemplateBuilder.sln b/TemplateBuilder.sln index fcacc09..e317303 100644 --- a/TemplateBuilder.sln +++ b/TemplateBuilder.sln @@ -8,6 +8,7 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{30CD1058-100D-42BE-8C0D-8FC425559D06}" ProjectSection(SolutionItems) = preProject .travis.yml = .travis.yml + CHANGELOG.md = CHANGELOG.md rakeconfig.rb = rakeconfig.rb rakefile.rb = rakefile.rb README.md = README.md diff --git a/TemplateBuilder/TemplateBuilder.csproj b/TemplateBuilder/TemplateBuilder.csproj index 632f822..c9f0df8 100644 --- a/TemplateBuilder/TemplateBuilder.csproj +++ b/TemplateBuilder/TemplateBuilder.csproj @@ -64,7 +64,6 @@ - diff --git a/Tests/DicomRepopulatorTests.cs b/Tests/DicomRepopulatorTests.cs index 4dfcfb4..5826016 100644 --- a/Tests/DicomRepopulatorTests.cs +++ b/Tests/DicomRepopulatorTests.cs @@ -103,6 +103,7 @@ public void Test_StudyDateTag_GoodData() } + [Ignore("This really shouldn't be passing! how do we validate that 'Lolz' is not a valid StudyDate for inserting rather than blindly writting it in?")] [Test] public void Test_StudyDateTag_BadData() { diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index 783720b..eb36336 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -1,7 +1,7 @@  {66EED857-25C6-4FF9-967A-333CB151DF0B} - net461 + netcoreapp2.2 {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages @@ -20,7 +20,7 @@ - + From c7325b83d0661b799105d5e5e320c43070341edd Mon Sep 17 00:00:00 2001 From: tznind Date: Mon, 9 Dec 2019 10:38:42 +0000 Subject: [PATCH 16/19] Removed resource files from tests --- Tests/DicomRepopulatorTests.cs | 51 +++++------ Tests/TestData.cs | 46 ++++++++++ Tests/{ => TestData}/IM-0001-0013.dcm | Bin Tests/{ => TestData}/IM-0001-0019.dcm | Bin Tests/TestDicomFiles.Designer.cs | 83 ----------------- Tests/TestDicomFiles.resx | 127 -------------------------- Tests/Tests.csproj | 19 ++-- 7 files changed, 76 insertions(+), 250 deletions(-) create mode 100644 Tests/TestData.cs rename Tests/{ => TestData}/IM-0001-0013.dcm (100%) rename Tests/{ => TestData}/IM-0001-0019.dcm (100%) delete mode 100644 Tests/TestDicomFiles.Designer.cs delete mode 100644 Tests/TestDicomFiles.resx diff --git a/Tests/DicomRepopulatorTests.cs b/Tests/DicomRepopulatorTests.cs index 5826016..0fc8403 100644 --- a/Tests/DicomRepopulatorTests.cs +++ b/Tests/DicomRepopulatorTests.cs @@ -36,8 +36,8 @@ public void TearDown() public void Test_AbsolutePath_InCsv() { //Create a dicom file in the input dir /subdir/IM_0001_0013.dcm - var inputDicom = CreateInputFile(TestDicomFiles.IM_0001_0013, - Path.Combine("subdir", nameof(TestDicomFiles.IM_0001_0013) +".dcm")); + var inputDicom = CreateInputFile(TestData.IMG_013, + Path.Combine("subdir", nameof(TestData.IMG_013) +".dcm")); //Create a CSV with the full path to the image var inputCsv = CreateInputCsvFile( @@ -53,18 +53,17 @@ public void Test_AbsolutePath_InCsv() (o) => o.FileNameColumn = "File"); //anonymous image should appear in the subdirectory of the out dir - var expectedOutFile = new FileInfo(Path.Combine(outDir.FullName, "subdir", nameof(TestDicomFiles.IM_0001_0013) + ".dcm")); + var expectedOutFile = new FileInfo(Path.Combine(outDir.FullName, "subdir", nameof(TestData.IMG_013) + ".dcm")); FileAssert.Exists(expectedOutFile); } - [TestCase("./subdir/IM_0001_0013.dcm")] - [TestCase("subdir/IM_0001_0013.dcm")] - [TestCase("./../Test_RelativePath_InCsv/subdir/IM_0001_0013.dcm")] + [TestCase("./subdir/IM-0001-0013.dcm")] + [TestCase("subdir/IM-0001-0013.dcm")] + [TestCase("./../Test_RelativePath_InCsv/subdir/IM-0001-0013.dcm")] public void Test_RelativePath_InCsv(string csvPath) { //Create a dicom file in the input dir /subdir/IM_0001_0013.dcm - var inputDicom = CreateInputFile(TestDicomFiles.IM_0001_0013, - Path.Combine("subdir", nameof(TestDicomFiles.IM_0001_0013) +".dcm")); + var inputDicom = TestData.Create(new FileInfo(Path.Combine(TestContext.CurrentContext.WorkDirectory,nameof(Test_RelativePath_InCsv),"subdir", Path.GetFileName(TestData.IMG_013))),TestData.IMG_013); //Create a CSV with the full path to the image var inputCsv = CreateInputCsvFile( @@ -80,14 +79,14 @@ public void Test_RelativePath_InCsv(string csvPath) (o) => o.FileNameColumn = "File"); //anonymous image should appear in the subdirectory of the out dir - var expectedOutFile = new FileInfo(Path.Combine(outDir.FullName, "subdir", nameof(TestDicomFiles.IM_0001_0013) + ".dcm")); + var expectedOutFile = new FileInfo(Path.Combine(outDir.FullName, "subdir", Path.GetFileName(TestData.IMG_013))); FileAssert.Exists(expectedOutFile); } [Test] public void Test_StudyDateTag_GoodData() { - var inputDicom = CreateInputFile(TestDicomFiles.IM_0001_0013, "mydicom.dcm"); + var inputDicom = CreateInputFile(TestData.IMG_013, "mydicom.dcm"); var inputCsv = CreateInputCsvFile( $@"RelativeFileArchiveURI,PatientID,StudyDate {inputDicom.FullName},ABC123,2001-01-01"); @@ -107,7 +106,7 @@ public void Test_StudyDateTag_GoodData() [Test] public void Test_StudyDateTag_BadData() { - var inputDicom = CreateInputFile(TestDicomFiles.IM_0001_0013, "mydicom.dcm"); + var inputDicom = CreateInputFile(TestData.IMG_013, "mydicom.dcm"); var inputCsv = CreateInputCsvFile( $@"RelativeFileArchiveURI,PatientID,StudyDate {inputDicom.FullName},ABC123,Lolz"); @@ -127,7 +126,7 @@ public void Test_StudyDateTag_BadData() [Test] public void SingleFileBasicOperationTest() { - var inFile = CreateInputFile(TestDicomFiles.IM_0001_0013,nameof(TestDicomFiles.IM_0001_0013) +".dcm"); + var inFile = CreateInputFile(TestData.IMG_013,nameof(TestData.IMG_013) +".dcm"); var outDir = AssertRunsSuccesfully(1, 0,null, @@ -138,7 +137,7 @@ public void SingleFileBasicOperationTest() (o) => o.InputCsv= Path.Combine(TestContext.CurrentContext.TestDirectory, "BasicTest.csv")); //Anonymous dicom image should exist - var expectedFile = new FileInfo(Path.Combine(outDir.FullName, nameof(TestDicomFiles.IM_0001_0013) + ".dcm")); + var expectedFile = new FileInfo(Path.Combine(outDir.FullName, nameof(TestData.IMG_013) + ".dcm")); FileAssert.Exists(expectedFile); //it should have the patient ID from the csv @@ -154,7 +153,7 @@ public void KeyNotFirstColumn(bool runSecondaryAnon) const string testFileName = IM_0001_0013_NAME; Directory.CreateDirectory(inputDirPath); - File.WriteAllBytes(Path.Combine(inputDirPath, testFileName), TestDicomFiles.IM_0001_0013); + TestData.Create(new FileInfo(Path.Combine(inputDirPath, testFileName)), TestData.IMG_013); string outputDirPath = Path.Combine(_outputFileBase, "KeyNotFirstColumn"); string expectedFile = Path.Combine(outputDirPath, testFileName); @@ -185,7 +184,7 @@ public void DateRepopulation() const string testFileName = IM_0001_0013_NAME; Directory.CreateDirectory(inputDirPath); - File.WriteAllBytes(Path.Combine(inputDirPath, testFileName), TestDicomFiles.IM_0001_0013); + TestData.Create(new FileInfo(Path.Combine(inputDirPath, testFileName)), TestData.IMG_013); string outputDirPath = Path.Combine(_outputFileBase, "DateRepopulation"); string expectedFile = Path.Combine(outputDirPath, testFileName); @@ -217,7 +216,7 @@ public void OneCsvColumnToMultipleDicomTags() const string testFileName = IM_0001_0013_NAME; Directory.CreateDirectory(inputDirPath); - File.WriteAllBytes(Path.Combine(inputDirPath, testFileName), TestDicomFiles.IM_0001_0013); + TestData.Create(new FileInfo(Path.Combine(inputDirPath, testFileName)), TestData.IMG_013); string outputDirPath = Path.Combine(_outputFileBase, "OneCsvColumnToMultipleDicomTags"); string expectedFile = Path.Combine(outputDirPath, testFileName); @@ -249,7 +248,7 @@ public void SpacesInCsvHeaderTest() const string testFileName = IM_0001_0013_NAME; Directory.CreateDirectory(inputDirPath); - File.WriteAllBytes(Path.Combine(inputDirPath, testFileName), TestDicomFiles.IM_0001_0013); + TestData.Create(new FileInfo(Path.Combine(inputDirPath, testFileName)), TestData.IMG_013); string outputDirPath = Path.Combine(_outputFileBase, "SpacesInCsvHeaderTest"); string expectedFile = Path.Combine(outputDirPath, testFileName); @@ -280,8 +279,8 @@ public void MultipleFilesSameSeriesTest() const string testFileName2 = IM_0001_0019_NAME; Directory.CreateDirectory(inputDirPath); - File.WriteAllBytes(Path.Combine(inputDirPath, testFileName1), TestDicomFiles.IM_0001_0013); - File.WriteAllBytes(Path.Combine(inputDirPath, testFileName2), TestDicomFiles.IM_0001_0013); + TestData.Create(new FileInfo(Path.Combine(inputDirPath, testFileName1)), TestData.IMG_013); + TestData.Create(new FileInfo(Path.Combine(inputDirPath, testFileName2)), TestData.IMG_013); string outputDirPath = Path.Combine(_outputFileBase, "MultipleFilesSameSeriesTest"); string expectedFile1 = Path.Combine(outputDirPath, testFileName1); @@ -318,10 +317,10 @@ public void MultipleSeriesTest() Directory.CreateDirectory(Path.Combine(inputDirPath, "Series1")); Directory.CreateDirectory(Path.Combine(inputDirPath, "Series2")); - File.WriteAllBytes(Path.Combine(inputDirPath, "Series1", testFileName1), TestDicomFiles.IM_0001_0013); - File.WriteAllBytes(Path.Combine(inputDirPath, "Series1", testFileName2), TestDicomFiles.IM_0001_0013); - File.WriteAllBytes(Path.Combine(inputDirPath, "Series2", testFileName1), TestDicomFiles.IM_0001_0019); - File.WriteAllBytes(Path.Combine(inputDirPath, "Series2", testFileName2), TestDicomFiles.IM_0001_0019); + TestData.Create(new FileInfo(Path.Combine(inputDirPath, "Series1", testFileName1)), TestData.IMG_013); + TestData.Create(new FileInfo(Path.Combine(inputDirPath, "Series1", testFileName2)), TestData.IMG_013); + TestData.Create(new FileInfo(Path.Combine(inputDirPath, "Series2", testFileName1)), TestData.IMG_019); + TestData.Create(new FileInfo(Path.Combine(inputDirPath, "Series2", testFileName2)), TestData.IMG_019); string outputDirPath = Path.Combine(_seriesFilesBase, "TestOutput"); string expectedFile1 = Path.Combine(outputDirPath, "Series1", testFileName1); @@ -392,7 +391,7 @@ private FileInfo GenerateTextFile(string[] contents, string filename) /// The filename to write out e.g. "my.dcm" or "mysubdir/my.dcm" /// /// - private FileInfo CreateInputFile(byte[] bytes,string filename,[System.Runtime.CompilerServices.CallerMemberName] string memberName = "") + private FileInfo CreateInputFile(string testFile,string filename,[System.Runtime.CompilerServices.CallerMemberName] string memberName = "") { string inputDirPath = Path.Combine(_inputFileBase, memberName); @@ -401,9 +400,7 @@ private FileInfo CreateInputFile(byte[] bytes,string filename,[System.Runtime.Co toReturn.Directory.Create(); - File.WriteAllBytes(toReturn.FullName, bytes); - - return toReturn; + return TestData.Create(toReturn, testFile); } /// /// Runs the with the provided etc. Asserts that there diff --git a/Tests/TestData.cs b/Tests/TestData.cs new file mode 100644 index 0000000..d3fe973 --- /dev/null +++ b/Tests/TestData.cs @@ -0,0 +1,46 @@ +using System.IO; +using NUnit.Framework; + +namespace Tests +{ + public sealed class TestData + { + // Paths to the test DICOM files relative to TestContext.CurrentContext.TestDirectory + private const string TEST_DATA_DIR = "TestData"; + public static string IMG_013 = System.IO.Path.Combine(TEST_DATA_DIR, "IM-0001-0013.dcm"); + public static string IMG_019 = System.IO.Path.Combine(TEST_DATA_DIR, "IM-0001-0019.dcm"); + + /// + /// Creates the test image in the file location specified + /// + /// + /// The test file to create, should be a static member of this class. Defaults to + /// True to delete any existing files in the directory + /// + public static FileInfo Create(FileInfo fileInfo, string testFile=null,bool cleanDirectory = true) + { + var from = Path.Combine(TestContext.CurrentContext.TestDirectory, testFile??IMG_013); + + if(fileInfo.Directory != null) + if(!fileInfo.Directory.Exists) + fileInfo.Directory.Create(); + else + { + if (cleanDirectory) + { + foreach(var f in fileInfo.Directory.GetFiles("*",SearchOption.AllDirectories)) + f.Delete(); + + foreach(var d in fileInfo.Directory.EnumerateDirectories()) + d.Delete(); + } + + } + + File.Copy(from,fileInfo.FullName,true); + + return fileInfo; + } + + } +} diff --git a/Tests/IM-0001-0013.dcm b/Tests/TestData/IM-0001-0013.dcm similarity index 100% rename from Tests/IM-0001-0013.dcm rename to Tests/TestData/IM-0001-0013.dcm diff --git a/Tests/IM-0001-0019.dcm b/Tests/TestData/IM-0001-0019.dcm similarity index 100% rename from Tests/IM-0001-0019.dcm rename to Tests/TestData/IM-0001-0019.dcm diff --git a/Tests/TestDicomFiles.Designer.cs b/Tests/TestDicomFiles.Designer.cs deleted file mode 100644 index f31dfd4..0000000 --- a/Tests/TestDicomFiles.Designer.cs +++ /dev/null @@ -1,83 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Tests { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class TestDicomFiles { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal TestDicomFiles() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Tests.TestDicomFiles", typeof(TestDicomFiles).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized resource of type System.Byte[]. - /// - internal static byte[] IM_0001_0013 { - get { - object obj = ResourceManager.GetObject("IM_0001_0013", resourceCulture); - return ((byte[])(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Byte[]. - /// - internal static byte[] IM_0001_0019 { - get { - object obj = ResourceManager.GetObject("IM_0001_0019", resourceCulture); - return ((byte[])(obj)); - } - } - } -} diff --git a/Tests/TestDicomFiles.resx b/Tests/TestDicomFiles.resx deleted file mode 100644 index 583e8d0..0000000 --- a/Tests/TestDicomFiles.resx +++ /dev/null @@ -1,127 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 - - - - IM-0001-0013.dcm;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - IM-0001-0019.dcm;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index eb36336..a7cb747 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -22,23 +22,16 @@ - - - True - True - TestDicomFiles.resx - - - - - ResXFileCodeGenerator - TestDicomFiles.Designer.cs - - PreserveNewest + + Always + + + Always + PreserveNewest From 9ec991510b9b0a4633b4ad47a0fabda5d014d387 Mon Sep 17 00:00:00 2001 From: tznind Date: Mon, 9 Dec 2019 10:46:39 +0000 Subject: [PATCH 17/19] unit test fix --- Tests/DicomRepopulatorTests.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Tests/DicomRepopulatorTests.cs b/Tests/DicomRepopulatorTests.cs index 0fc8403..4323e3a 100644 --- a/Tests/DicomRepopulatorTests.cs +++ b/Tests/DicomRepopulatorTests.cs @@ -279,8 +279,8 @@ public void MultipleFilesSameSeriesTest() const string testFileName2 = IM_0001_0019_NAME; Directory.CreateDirectory(inputDirPath); - TestData.Create(new FileInfo(Path.Combine(inputDirPath, testFileName1)), TestData.IMG_013); - TestData.Create(new FileInfo(Path.Combine(inputDirPath, testFileName2)), TestData.IMG_013); + TestData.Create(new FileInfo(Path.Combine(inputDirPath, testFileName1)), TestData.IMG_013,true); + TestData.Create(new FileInfo(Path.Combine(inputDirPath, testFileName2)), TestData.IMG_013,false); string outputDirPath = Path.Combine(_outputFileBase, "MultipleFilesSameSeriesTest"); string expectedFile1 = Path.Combine(outputDirPath, testFileName1); @@ -317,10 +317,10 @@ public void MultipleSeriesTest() Directory.CreateDirectory(Path.Combine(inputDirPath, "Series1")); Directory.CreateDirectory(Path.Combine(inputDirPath, "Series2")); - TestData.Create(new FileInfo(Path.Combine(inputDirPath, "Series1", testFileName1)), TestData.IMG_013); - TestData.Create(new FileInfo(Path.Combine(inputDirPath, "Series1", testFileName2)), TestData.IMG_013); - TestData.Create(new FileInfo(Path.Combine(inputDirPath, "Series2", testFileName1)), TestData.IMG_019); - TestData.Create(new FileInfo(Path.Combine(inputDirPath, "Series2", testFileName2)), TestData.IMG_019); + TestData.Create(new FileInfo(Path.Combine(inputDirPath, "Series1", testFileName1)), TestData.IMG_013,true); + TestData.Create(new FileInfo(Path.Combine(inputDirPath, "Series1", testFileName2)), TestData.IMG_013,false); + TestData.Create(new FileInfo(Path.Combine(inputDirPath, "Series2", testFileName1)), TestData.IMG_019,true); + TestData.Create(new FileInfo(Path.Combine(inputDirPath, "Series2", testFileName2)), TestData.IMG_019,false); string outputDirPath = Path.Combine(_seriesFilesBase, "TestOutput"); string expectedFile1 = Path.Combine(outputDirPath, "Series1", testFileName1); From 219d061e99fb348436ee99581c10e40db9bb2aa0 Mon Sep 17 00:00:00 2001 From: tznind Date: Mon, 9 Dec 2019 11:05:34 +0000 Subject: [PATCH 18/19] Added integration badges --- README.md | 2 ++ TemplateBuilder/DicomFileTagsUI.cs | 2 +- TemplateBuilder/Form1.cs | 41 ++++++++++++++++-------------- 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 194155a..d7f5a60 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # DicomTemplateBuilder +[![Build Status](https://travis-ci.org/HicServices/DicomTemplateBuilder.svg?branch=master)](https://travis-ci.org/HicServices/DicomTemplateBuilder) [![Total alerts](https://img.shields.io/lgtm/alerts/g/HicServices/DicomTemplateBuilder.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/HicServices/DicomTemplateBuilder/alerts/) + [Dicom Template Builder](https://github.com/HicServices/DicomTemplateBuilder/releases) is a small windows application to assist researchers in building simple relational database schemas for storing DICOM images. It supports: diff --git a/TemplateBuilder/DicomFileTagsUI.cs b/TemplateBuilder/DicomFileTagsUI.cs index ca244e5..74a08b6 100644 --- a/TemplateBuilder/DicomFileTagsUI.cs +++ b/TemplateBuilder/DicomFileTagsUI.cs @@ -53,7 +53,7 @@ protected override void OnLoad(EventArgs e) } } - catch (Exception ex) + catch (Exception) { //no picture splitContainer1.Panel1Collapsed = true; diff --git a/TemplateBuilder/Form1.cs b/TemplateBuilder/Form1.cs index 35b6d63..f05d0fc 100644 --- a/TemplateBuilder/Form1.cs +++ b/TemplateBuilder/Form1.cs @@ -373,32 +373,35 @@ private void btnAddDicom_Click(object sender, EventArgs e) private void OpenDicoms() { - var ofd = new OpenFileDialog(); - ofd.Filter = "Dicom Files|*.dcm"; - ofd.Multiselect = true; - - if (ofd.ShowDialog() == DialogResult.OK) + using (var ofd = new OpenFileDialog()) { - try + ofd.Filter = "Dicom Files|*.dcm"; + ofd.Multiselect = true; + + if (ofd.ShowDialog() == DialogResult.OK) { - _setupFinished = false; - olvDicoms.BeginUpdate(); + try + { + _setupFinished = false; + olvDicoms.BeginUpdate(); - foreach (var f in ofd.FileNames) + foreach (var f in ofd.FileNames) + { + var fi = new FileInfo(f); + if (fi.Exists) + olvDicoms.AddObject(fi); + } + } + finally { - var fi = new FileInfo(f); - if (fi.Exists) - olvDicoms.AddObject(fi); + olvDicoms.EndUpdate(); + _setupFinished = true; } - } - finally - { - olvDicoms.EndUpdate(); - _setupFinished = true; - } - Check(); + Check(); + } } + } private void btnOnlineTemplates_Click(object sender, EventArgs e) From 533e87325924aa54086a0e3e1b43670089631b99 Mon Sep 17 00:00:00 2001 From: tznind Date: Mon, 9 Dec 2019 11:08:25 +0000 Subject: [PATCH 19/19] Bumped version to 1.0.1 --- CHANGELOG.md | 3 +++ SharedAssemblyInfo.cs | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index af87010..35cc8c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.0.1] - 2019-12-09 + ### Added - Added initial iteration of dicom tag repopulator (anonymises dicom images based on CSV data) @@ -17,5 +19,6 @@ Initial version [Unreleased]: https://github.com/HicServices/DicomTemplateBuilder/compare/v1.0.0...develop +[1.0.1]: https://github.com/HicServices/DicomTemplateBuilder/compare/v1.0.0...v1.0.1 [1.0.0]: https://github.com/HicServices/DicomTemplateBuilder/tree/v1.0.0 [DicomTypeTranslation]: https://github.com/HicServices/DicomTypeTranslation \ No newline at end of file diff --git a/SharedAssemblyInfo.cs b/SharedAssemblyInfo.cs index af3efed..70fa76d 100644 --- a/SharedAssemblyInfo.cs +++ b/SharedAssemblyInfo.cs @@ -7,6 +7,6 @@ [assembly: AssemblyCulture("")] // These should be replaced with correct values by the release process -[assembly: AssemblyVersion("1.0.0")] -[assembly: AssemblyFileVersion("1.0.0")] -[assembly: AssemblyInformationalVersion("1.0.0")] +[assembly: AssemblyVersion("1.0.1")] +[assembly: AssemblyFileVersion("1.0.1")] +[assembly: AssemblyInformationalVersion("1.0.1")]

u|ipkAWG zv)K!3yly(UsrKi_vFsWpraL=WmwqN)7P_!nB@5FLKa(hliM3>PqMhkD_)#C$@^)hM#F@`wa3BoA) zKa&V#W3I#PiVktQrl=eoc*d|sx~Cw!$4O9IrZN3-0G+E^(QisiIWjaVUHimGIce)k zHe6N3&y$RPcaLT_hRgz$E>Uz4q;P5Na}|kA_MbY>oSyRo`E!VKFh67jA3sP~n!kqV zjj3=E*VEX`9qCA#?O);Q(xO(G6VHJ!Cr@NoBImLXM4~4+oZ1AfcYbHTQn~Zr=E|*@ z2_{CK9E_`7-%H)Q5uR_tt#qzBmOg7gMoq#Cj(D%8k9hx&s086tM*E?WcO?oa4Wt=?$JmRIRa*cO%sY;dABUyRW=B9Z4B zFSJecD-;PnqLjL*NvN3C-kN>go}5t%WAdp^f@~m?#@hD zaL;Q3oa?i-oCMLrc*#aMkpiV_#VXVU=zJ$ zx{SLb)c-{l$?onpE(s93G|XiYAWHJvXX=s&_BU1^%Z=t4b%DMbx3FWFA6|z!gcNz> zGEaYsCa@(4k#=x(auyUwK+;+oU05uvzqK1~CoTt@o82!Bf6NcF}}H{+)}2^=vNnHcw}H~OtMEsgt;+;^v_Tg-a= z$@L-=FZy{*r-L>_M~|v@ji)6nH&M~M%T>KK<3G(KU`-N1@7x{R&VSfjzQRZw>|5LPb`vWOR9Y`?z#sLDA!Y9+!LTX`R$?wZ*Hsh zIXW{!v*zUd0w9X}neg&F*VZ=Di;n3>j32r^B$#q{l8&-l6ft1ObIsj^4*dMJ7QXDH zQ;Un7kk!GE&6QdGxy6C(TTUoRh*}5M1*uh<4i`Y#zLkyB8r{XXib)Gpo@=|-FLmPy z#0%2+%ZW|!Rc5=f%^bd3%Cl+tQ)EjY+rc@lx%7pQvdEKSv}$qSby4D%60&DOjRLHCBB=ejK>h#(+`IYbIdxiS8RJx^$CN`FfPC4h4a-oL*;{ioQ#t7uvq=f~1)2y9AZ;z2`;+>!?6C!Oyj z&P)Q~23wng8-47Ci?$E#^$))bhGwx=cL@C*S4*j*lmLc z)sUfOhfcGAeC!?lT-Y!75P)sdHD0I;_68Y%fOBGD<7A9Gx-9;6=94sRi7<{NI+%DO zZ`OF0L0?CJ)t8_J+!LOwLoBA>^70bm{k-ijQYX=ow|tQr#x9WS{b#e}5-_6C59UmD z))9PCi1+9}g{Rp|kXF5uyEhv9D|=AE$_*QL8gFkJDMgkD-Dm8A46Tf27O$1i`Ed1Ip|vdgFVQ{sI| zVqIeJ6i%KWdV6;c*QRp% zU3F5~x_tr85LB+HfZ^WP^2_K&;NI6*uS=xfh*tSFp!(w#<$J2>E+!3iuME-sb4o*1 zcPPxN_`e?@e`FX%609-%b-8gYqe+Od7tP|U-z&x1LAyOOM;k+aQ?}{haJc~geW<~g;rU)H z>UFrv9!{3EZM!hS%Ojgo?nOOS=x#;;8pnBDXq?T_%73a(os?J`MKJPg1{lFZn|USu zVy80iN6bql$4LIe?{Cl*)+RCWxaiFOuP7Q59Owy!1NtX~^3wMz^~n4KjYI^1ao-yv zBVko!py`5W@#4P>%P3{rXe^--U{)PL{vp|L;4 zmU#U|l!qhr*OP*s*y_arfp>P}#wt=eo}i-ZHUCkUnQ%M@i&d)ARm}kofw>x6 zNBWhl+Ga&IwK`qaMvk05mTjd)L=BFsTZVT|B{t(v^oQbQc$fyOf!BX9@^kXDz#@Zn zPlQHEGs-yHrBrf#;zetwTAcQ~c?+yc*-1xN@VL7 zrS(~t-QOZu$|V-!q$Bb1o72qnRt?kQD~X_R1A|?s8j5kJ)5+xRvTD&3y2Y0;ShkTItBJYjEIsa)=zevA8PqazC>2Y`E)HVEZnWgq7 zF0skv5*44+-pPC1rC1Qgc^SV`dr1puF-XoS9s<3CY?CAv$tNO8Eh{yG?$%Mi-Q$Zm zwjD})gb!YGv8Vh`<$-cwl+?M(1<`uY}MDV7k1>=DQGjv z)G=^XEDF^TrxGvOYDe~Rh!0p{Zs~dK=Jz_$jn%D#V+2R|duBDp9oL-uD@VM4>&DR4 ziBAY!&03o%f@6B@?SEK*$c>)?OkJ_wc>H#{I2`4O)j{8!ye--P(@G4(%w4)Yrf#ku zKkL`8ohVY9rfRi6t9eoW$bvBF{}j_iEZ^e%OCUB=v{5$_lby>4O(nJNl)IZX+lO*u z0mtvJ7|XWDJImmjl8$s&>H}L>uWeI5&+ma>oA0pafvDpXg8H+~jb6yteXJTWONGm> zilUtD!KUsrO+Ss!?%G5pI9tz}KVh_NWR1E4(iG^ow7kDPAm;^vPI6xeZnS>i%o`S) zJ+NeV>YIpsP8IL)LgENLO3l00;hu$aU%h0ME%k%UagQ63oP zgue5+*o?(*4iWuGt{h}&bCe4ZsVhz<&^P0VBEgS}Q4Z}>?EhTq8QP&|A9u=z?`=XS z(#wZ!N0S@eN>Jj&U680bF^cEWu*3=%%T%bhlgQtQ1``_;l57JGmnhJ)wl0_j`6771 zse~(Lq>b+$k5GOPSNda3J1bNDDSlA0@7wKL;%a|c|N8zMkP`wL?Y{_rw*>O-A1A&k z__R55=Iq|A%tTNex;iAavV?hQB}#SW)~%2a)eD!HNS_dd@2V)U;FnHA_>KDQ?{p%d zG1C!{S2Usqj{<-zYY--pA@kkm`1g`*>F+%<-Vz>_u$crn+5x|6#r1wwpf-epnopM2 zXW}!$*_At09dY>ms%_Ft%EY@CEi=@{8}(EZIm$ADwTp0~Q66*`((JYr75Ues>)Oxh z>7I(BK#vFYi?NAJssj~%?cM-o@#mG7K7W%0d9&)D8J<`LXw0t!&%|`+WR@>*)p{HM zpu~FJoMzn|^J!to)c3iA`-y3|j3~bojuy#I^-N~#Is59Q+-Y>}J}KeRPTCLeq(i4G z#ak@h+*5DW<}5a0rfo}j`Va<{LUd=$B6aUDOM+vdsWPn-7jCj;R9_IN8?+6Lv01tM zEO_iyJAe z*4uBj$NrUoS#*@3A3(MKLSu?Y@8|4~Sdrup3sbk@eq!q(ZH=cSH6y#;t-W&NaQ(V8z~S_1_`-$6>zC0PSqkE+_}DF#W=mRpxf} z;qA^dx~@L~_D0l(@*C4ib&WZY>0o((4P<5;3SjCf-PFI-$GKJJkAGXOe|#%ot?$@5 z(Ehb?Lnn5WQL21e`kZ?F^(xF#nGUT?;Fkw%l1&Uz7Fvsr`5u=Vfwuke#lTKAf8ygt z(!t`nVv_s$>u7-#xyrW)xtPyN#VdX9+fe3dKn=f(Q}sfq>LOegCY>fXT+g+WF{{+L z#XpNerKjVM-$hjJJq&gqtmP#Bih3Hd389AB?|V@^u5Th^M0Pe*7f`ZWb)9#$b}O#8 z@+b6weyPmuQ$g?bHWpjvk-yE}1=)RFmsIFtY{P&2@qN|}3F~!!Y-R&V9>?G^!`)`A zezwD14MR#IN;5}ISUKz9;`OK8Of2Snevr(CK|>gR8Uf*7dJVJ$8V(`11FZjczPuY2 zEoB8L)A!;I}u`{qNCUs1zU||AbD}EKv#IGmuzyVD1WvWencNg^6tZ0@C7kATy6=|Hebm20qK)#` zZ@nwi3Np5*CnW-x=!d z9&=2e&v-AS_YZ+H|Df0>sd7%FTc<1J9j`I^T;jx6xDJ=EXonZ7mEcOkn+-O~5gN9R z#}1qrlkZ>M;B!L+ZC?#=Ocz?B%eR~`0IJaaZtas_81bVrvQa0d`we5&YVf-^{Yjt< z;XUVd_XZc^&i!g5@Q1R-KxKQ(s)A88(JWV`oNU!sL3#PPV81HYGMHaGJQKQb4#sSb zVChPwj?6F-rHF9~D0CY4c4bnuRugPw`G>p^GL|ApLfKifFMNVfp;)Vfc7DUzp2OS4 z+s)|sM5B0?IN6+OTlj$g*%Jx9*(h%Y8P$4t1{g`M@^GMG*ya73|H3ZyiuNIh$41DN zOJa2q&W_BS7{X;Gem}zWBeD|7DMqbGE%$)3fRzS<5N9VzqyrYW5?a{nl~K z6hJtNZ>R1C_sHECTags?O{yY3^wkuKFNCJ5EjPgbo4F1nCaPi30)EHmrjG%aAjJ|$ zB&&L9%**rU)raDTeFW@JeSm4;kKfV2r~Z#>z?uqZ^+T_JDE}k`nz%b~>>iM2j%h05 z`>WwNHE`)>x!ELJyH;`Rb(OVv_>DyG6YV(H?$KW)As97K%pA$O+JcSNx#-IaEv5rY z*m;!^BYq&$;z_*FSD3Dd$y z;Zg?OOOE8SxzAetR9~%Q?H%d0YrLz;KWRLm0u&amLrY{1wI0Hb9Wj_m9C?>OVeqGm zc@50yvmKh#B`RNi${CW8B2Ah$DXluU@sM3aAsD}dse#|#f;f5He1_FHhlCnyBzYwg8j<#Wv zpb62lC3}~JNvoBoIU14*FmQt@B{2K|oYc~xM;q6(VAS?f*%JhCsXhY5e}Czy>v`>0 zosE{9g0{`7*E_>h3vSuAyWv>5w=nq2twL%x^uoXlAz@#w&KAR`FClyi#?uk%<|fne z%+Kzoiuf03ZcY5U=cch#W}d<9TP2~765 z|4!S#GX9wUw;bXWh(C-T;FgE6`B-zfM-WBYycDVs!v9+2%Emr@a&5r0n#nV%m9-#7 z7SuSM=KofeVBrNU3>8l~@T>Lsx$z#9p`y9?v0lC#q{{H~(TGq=J%v@#zJiFSSPdFV_etSqK9YpGtY!XXl^k z_V7RaUnp)&1cCy#fl|$6BV_0<-8wlSi09hN_q_iy`P~MB7(PV&2gOx?|L|cW1jgnG z)wc9uk%3i5H(PMLgCpviELVr0q7b^Cn#8L796ptcggSOKYK|IqazJn4@Lgg5Pg!RD z;(5H$^#Y@#fzv+IqM|Y`oOOIfUcH(_zcHr1woRqxG@$HVT4nCTsKC&ZDf+hqP9vrL z7e22`SmQ8v%l^?%?0T%3Ce#n{x$*M6% zhsS#H`qnwlRA}SzcB{_cLHbr6W-;>B**4nzpv_U>2VDo2ynJVGc3;r_m=S&C40 zDYj#Z;AOxPT5=(>1vp(2uosMt(JMsclR9cxmbwl6jT^}|4RGY={35mF#l^>*;YDou z->N5Rhg^pX^QV7E#**iVeLLyAKU`QG-c0A%Tji;TbF6$D3y38BHDowuJ#KzQKYEv! z?OI$Dhf2M1C^e29uR!nBO738=ek}zW>&m~@sSaR2A_1-Up}eWV|B2kwBzn=P{u{pn z+%JED45aM<5&Op)AMU^q-^9ViNFnGp?gY&a-dI9UL)d7wW}T|Q9Tp1ELGsul#kqj) zOowrF;b1AqZ^6+}ot@ac?7drdsg8q5OUp)tCstY?EyEE9Hx62BTc#thbTM=$^NR$h zbs$5LqaUB40X+d{#Wygq6+pA-xYl`DT0CGjK+C=?)rOX3n<9+SsNG$*LG$pKjs$r6>h%w=UF5nH^q6 z%7C*>nayy`OYTT+bI=o68S{6BoEL@lHAXM)jPFE_i_E{Pb}t1OkkIolngz-Z_&l(s z;Z?s~>>y}Wv6wBze2TAoiFX8SDttyrZR9)*D>>4NkUSarEF;sZyPcyis&9lAt%~zB zssJ+i5ny-vcj;y=Kc@@DO?EZ0jo}vz1|2K;?Ycb+I6wpoV>E5Wo{ z3#FSQzTDx-@5CT;tnXa=gMrHy+q#J=#0%|GL3QJgR!mwk%f+s0?Y$IhhQR9?iKMkf zKBtWU5dg37Jl5J50+|km8BKR;doMrkY;NB+`}Q=Qvo(sAx5?*mk*-f$@}!l3*s&Xf z)1F^r*}2_C8*6^jE>r)1)sJHWwyuL3O3T)5aVnpy`M&wxGz!o6uAaH}vRtv8;If?( z*EJ5OOC;^H7thUBVf~@G2=W76V|`Ig5rBm_A4}J04OyL6ZO*gz3tc{g5tZic%qcmH z3ZWS=gl?1h3`LSr7bXdd=Kc6(?NtFRzq~b?JP2*0Go_A!)QP-du&whwP{6F2U zPZHH8CvL@W>Qzm-!KX%-NqpYXx#E?F3MsM z@^B_)K+W`QcYdmwDd=2v*}qw0Bk@V!G--fjX*z$bR|L`ega<6R)l4t$O-??lTmm7? zr3H;OvWaK#E~JFO&>-!QRe^9^0XkYb>8la)aQy3Oh31v}fi?#sNb<>v7U#2h+?U2j zwbFGYcEiUcM+^0>BQh8fbopLKe8ly?s)Cx%wJ}ya7ByP+}H8V-u|#6;7`z znSWx^PMZ;Ao}w7l9-gh-g*_0(H2UsoXl45>)VFJ;nitgKF)3w%3gzcOVqw$Bm5ugo zsrK!fE4|}?P^~jV0@t3f&2^g;>es^f^!KgI`?VWPT$&g%>co+{lTNwi!z5(uI;~qX z&XlUncI(1x!ipEqa3a)(BV(aVb?d%DQ9JY{mO0F>eZ8`8^BWN;n2SBben98*IRw2< zb&_ubuwnxcs4gP6<2(vEETb{Z-#jzs_*R^c*m0$TeSDh9BT_Ve+#|}{qXbz<{4tq3 z{zjMSJQN}n+8!2}y(0NP1z$Qw$ntCmjHIJilZy$6q}W4vcLQStkI~%S6w{_KpV=;a z-l5S%z`*iTabv2*@#{qCQ4h^Xo#@;0^Dt|}g05fPEC&|#>j!yS04nr*s{#OfYyrPZqiqkYNn_M3gh#+&HDw@b=vk9R7?%*R&K9#Acj#|@R&@7Jg+-o zgFKLw5-HXgJPHFn^ZOPl0l)H$UyHgAboNuB+<=GZdsV~U@$>l9*;fjRwF{S>S`N}q z+m^R7-Xh`DdP@=Iak{fr;xRT35__> zmwkik3xDP(3Oywqi>(vSCn3^9=`0A0B2alkJy~d?%;qh6B>fowqJibqSS2>zE~rlq z&3=8;pW8U(4}_yZq;$J-v(()m!k(|^V3OS*|4kTZeD@yyfC@1eeI!A`L-1ZM|4+7@ z06ZE0@B_}l=kvUqXP=PKszn-m;Bh#zrdeN$^pS3N*e7xxNX<%rLIX~9V6}Ayo624O zQlKd*^=B>4Usl$r)>kQ<^qrqWb?N4tSzu`!h9ciceaUEQD_UUuQTt-I^=__pa=J># zT(0lAix{&lob6;@j7c&%8Mb&WP8p2(n7$3~ACdy|kBePbbFyLPlV z{zWn01v3@U)#jG79<3iOqP=2C>n|B+)irC-{rF-O)Gcse5neOCK{iQxIcQ9|D#+7g z-?NB*C6co97(4Ck7cIwfE_@r~xRtGI&Sm>1a71q29hj3o*NLogI*RvM%S3>o-cNrv z92_m&=CVy$hY)i|CB>xWyEZNw(z*MwKy{(hv(EW=^Dz3Z{ZaY>v3sxsXUR@^RN{SS zc#AxkWkAEAdML~%qwomq*eP`Fn72>wZz|r*<*q&_n9zZV0RR)qMd7K&Mg_< zKm!FPqhj?c&93Ta!F18imfhnej+zatvR5Zo(f5`efdLW16t${HQ(uc7cze|sZjPW> zFY|J3{FNY-jaoSHS?J0p6$k7ZLB|&3U%dPgUFH|zuuLt3@Sc8|Kq@|#YUgcdH%@yT z`9eL?t9A-_vU`bO+aNEHwcu{iwG$OC4P-4@)*{FV66PQcFU)+wt=0+gZ1xx}SMP$3 zq;-`~jF)oaf5N-izkqoaejj>!{}Atw-5=j!A^|x=9`DQb&%fD&qz=H3GRvG61TgGx#XlBT}aH*bbpX^z|2HGX^fD}QhnR{w+yV| z^Z&j8H0`U!tbDm16neGti7@98q58O{26d4fvbxjyIJjRs|3N7c<1YV$G7GjkSEb#p zX@Zj?Gjs+H)?g(ZT&`@D3&`eVc8%6QXgst{%Rkj$V#d#*b2*Oyc!2a!ewguG)+R;3 zLU1J6`SQCE}RXr<#WaNIB7HWO|P z!*gs!rt=9)*n^*lrfuKicX6JYDPe~#4^o*my7bmnicnU8g6x`yoTq&Wf|g&h*QIIC zeT|FaqP055g`2^mnj3Q#!B&}>N~&EOHl})Ao5zB^skP)nvQaSTQTbkB z?)Q1XYc(b|+s@Y^H%&NxQm)9evAmuQ0~PBY`|?*X=N`@2whwK5lk8@MPaiPzi2!kc zQ@>JGei|TIL=!oU`otuu|Bxgkc6hTcG7>W!7-03^@>8Fr>ITG2oGo^QP?7!t zY&QMY%KbIp8~NL#FRw|mDwN#X;mH5DBhr;ORm){RrrpA&4^k#lbd%vhNL{XHxa>HeMJ9fUJ@qk*z=`b-*^ZM~aWVCX?S9e_=k% z002-HoS3GdRkd$do#87S~}yE zIe_v)Ea)qbacsr=j2#}T?F6t5k74B=H^UQZ#1W2pU7-?b7Aak!5Ro>>g)>68{&Ur; zFCIZ>pZx#P1<{^_Q;~0)+CaZ9+#)Eb%5!2x=ge)hgCgMB%2T`Ns#dA=nGfx>ey1y7 zCk)59rpRj<(+~9SxR|(S3HSS~;umR`<69yCbHgjq+U&bf7H^@K?TVwf9kC3v&IEGI zv$W%jE?)S_DR1(MA4;Qz>JyviVAX0H(2L)ts(y>u4Aa``_a^nq6f6GDmjbss%t^c6 zeLcAT*m|sVY@X%Y<>Z{M`lc9Fwji~m3|phL##?Jy8^GMlcq@nug3m5Lg9=zYK&Q8S z+_a>9Hzg`9c;sNiGLAq`x-W{zdmcs$MWruE+lo33nDG1TydT)Gn;at<@ngy2?X2a% zbl1Q0^9~Bmf6Goo3C0RcZupwns1LuKK|@pV(=;-Z(y+iHH%FXZra1C=eJ8_h;+`1B z*bAp`Q?qoK-5inC#Bh6e)*{dk<5HxFSD?kF2q+FPaukti|ETh3nAh<}c3Jt43?H>XuKuu_U-jVr+gU}KJU0=?@81?I;NClJ*DzZbRl|AN zeyFoPb#RljCO73HvEDW4av0(V{u!XG2WQDO=?#RqvQr2 z%H&|9)aE?+;W|?8H`-xx)+``)%h8{8YEtuB^{q29Ck4Y9U5sl@oUI4$E1i@YhJPlP z^!Q#iaK7dQ{nsgLm9%y=cyv@d6K&I*4!U@B-(r{NvPHFst($h!D>bmOs#nqt8KuAY zawQ;nW>0x;Z<%Gtwur^xGl~mG%e8==Y}0QY2mRB=)(f_Hp<(gMrcq`o3mqxBmQ6$$ zo<)V9turrm$1|lcXyX&kyjyhf0PX;(@G;i$<$5$rpw+?ZKJAXocJv_SjTrIi;JdtA zCJhy8XzUCY&Sr1m&rP!8Uz7d^8&bp=;PAs~OD;Ra{}!D=;B(q>xZPN6DxKjMl{7>& zM6~fhM~sXz@)5=bqRg%ys@f?!gIMdoH1gn$!ehB+eQQhbE&#=GgzsDTCAWToA8z%_ z`t??N&SU;!;QT!JW8CS!{P-r14ck?Iz2`mTlrjCm_alq!T3n@bd1JzC&}>;TLfk~q!tNE4;%H685==kackY68$~v#`X05gVeNRNX(X}u5@3)Q zTOePd4twE0wpsLr1R6Kli&i97rV92`k}u~>uU*&G+ad4om0fIR?0|l~8n1Hyv-b*I z{z%PQo}zM(Y1OO0PIY^RaDkdAm%<=twoz}9iccqpUMp8p_W;r$Pah40&nnH*K5$G$ z?m^NK%Wf88@sv8q9YzW^hjX%lY4Chk zEj20;J{5SD+cC0UIGczG!7ga^Z8F!Qf7y7BOvW=f07o5V>p*oTehJtnNYt_oizsrf zJWJ^dmbOvx%LY#V@P~f{`cD0NW!nAx70J4bcNmzC-!_WPkb85DJ=K-|>^u4Y zo&O*PWadwx6RJCE#sDejFKV~zln2t(g4;w_mFK?%lPon|=|pV8NwzR4jG~9loGYSM zPxSBj;!1W9eip3RnnW$PPtDM{=CS^avxIuO@!U&GntzwuFwKd6Dps zS`NQY8?RQ?AX72KV70!53)B`YB7-%&SZ>=Os)x?4a_LrUXeBiEmjRm$y#cd#+EI}z zqmGO4VU4Yp%dQEvYt2|qNhQ*stj7lsws1>UJy=#iDLq?1X7Zc0>aG->u<462d`6@v z<|}-=hk{6l%nka)ULRbB+^sqh@TK>`Gpy0V_tbc_au6(ArSO~wo$S$x`n9ZB#G_C|O3 z?)GU{Lp)QvB;2`QqH?Zp57|@XE&$?(siMAlmV+LGjixxG&~4o2uN`eQ-kE2B^H5)T zQPDB5fj-e)b;SM&33al1P_UhHP1b=)R@u731jU49nZJCfL_nVZ)TQQBWwSGGv$a)R zy-ujNfRK1PQD%MO7N$l$R`=92dt#PIm3_5_xl#CnNX+gZZm*HRHXI(?0CkJLiJq%% zp4=My=AP+eV$7=g?6&|i$$hqzx3svgKKL}~DjuUB2gaz@(egBo3;LL!>ng2m{nPBY z7w(;M#tJ_3GBgxkY`()V&sMWwwdlzo_i5ZI!>Iddu*qLnG|2`;!l9^tmWdWo=WA$k zhW#9tun=cpZ@C0}GEh5|%9+?JNYagoPp(fzNRu{545dx?-{YLRM#{O=zV$4$ROUeA ziFYp(!;X?%?|QShm!08jh!Qv8JNt<=?Jbukx9&Oa+{C9rNE9ua5Uzr|kNL~BglO4X zuf{9;rG1%FwKJho?(nM0*C4aMRn3lNYr>w_LJBiv?SKo4k3O=caghK2{f17c{0={T zK2^#37BKab)XqXBBG~zlD-Hr|wb8PL6~PoWX^DuE7*2@tGt<887tU)(f?53AX|Z>SVWm@l#?mVTz0RqTzf~710aM z!#ev%I1D^|-lK zuiwULPPG@R!CNaHXTCfVn%Sl;hALxK8r6^y9f}$Yk#6T30rVG&Ke;xH!x!zj<|nFm z_H!DsIgct04+mWI-mle~gla4@+AY~jUc1At5AX#l;NtuF;g(tR{v#ky{BD~uC-Dm1 z;2}+Z)3=@A9yjP}ZFpp(jZ?S9ZT5whhTDB^FJ98v*l2DiMviVCTR&kfoRe~mT&Fs4 zK4^TLAl>pKAYXXCmh&+JqZD79S`HrdRGuhY-Pr+CL~uUpy#>(&-G%dFAXtM@|>!K>T;i-Xpw zh}du_W)%%vHwS;1*Dn#GOwFw*bj&tea*0>)-*h+?TTqKNJG9QA<#b~SsRoc(6!Agr zh+0vi-Fv6ias|h!A-o21dUGLjwoNP`22GxtB+=O=F4+79igz;j@G?vRx2y-m5*ngD z6T{hiH@xexOXy6oIa@U+FS2CTw5|{MQzY-=_vW)sQ34464w=LDfX^EO!C5no*cL{- zATpu?rQes&KOv8a9U*y6Yo?19il=@?`KCQfb2J;&f<@0hx8oJ7kWg48Wl3*cG9_-G zDl6k@{xNgUP}}%uG736tQjkF$*RS zQMGVgM{#36Q$5A?LPnK-UFVRc@9oE>N)nO$15|yL`){Wc^+2@l%5Nm|fdURyckKnY zrE@)nZZmr6sFnd|DZg#`bD}v#)0ek@9eGfzrEie;>uXSFdNr(UN8eh zQ%Pi@gcWHBcinfd$gQasjb}QP)T;-p5rRRv5LJPwbG>d7o^~o~2hqpGTtH#e~s1cv!GuV!f8s7cdB}wOflE8b^4yj9@WasbhUB;`*>Y09WPzS zi<>QhXT4G<&J%X-tV_3s#|iz&-EfT4W=v2rVQWM1h;pn& zJIAe|l{g%d=JSK4O~9y2EFnu$_pl%Jh)olfkL5_$@>bq*G2;m6QeH39IWOa~cy#>0 z87TeME^x`1Du!p*8d*cQ?9^~D&xDnqqoGE*);+thqd#iM_lrVAj}=xTjMC4;=UACr zr&=sUTp~H51NTSz+SQiQeiRO^*3d8KRsyp8Qyf~F_;OAD)wWAV)#AKN5#26RBI$?^ ztCUzFT`N)kYv_}MQ%A2)dU;Zsye^HC#FN!(Yfz|ula}RbspI0^xjoK=?OW0m2?l|f zXS3}N5A)^dW_`%Fe z`GIUjRQbhg^|T)!atuWeE2!mXzu-O68Q+&T0r~+?$R7_v3U5fjocw!suwKS|CD?yn zOP!UT+dhB0EX1?53I}Cxw`Aq+pvMFy6?pt>3NU@ly_P;BI)T(hPCe%`1<&6@n%M5DO|eG;K7za;c_9XsVVPFK8w0k;Fm|bKinVzqA|X;uGID)3s_7S;b;p{qYTEsqf_yu5=l)Ey<{5 z)s6n2U>^C+KoYE(8TcJFsj0;I3HQuTUt=c!L0R1*QO)#X;nWrY5OXiSaQuU^k8xj^ zwAr<~Pn5ws=~2E>M*CZ9#$mpkPc+ncjYU=)(7@x$1vm93>JdS*5<%_8ibE@ zty?yktv;p+vpx=>rEFo88y=z1k&vV0qI$aY=OQl40V;J*1d|pT^}lG?*MZxiq2&*Y z&uo}he*LsjZIs^|ZATxtT@=8r_UJ`Sf?sk{jtQN-aaTE10pG3Lqw4+sj&XDVnIFLCOM_Kf>Fj;C{;xE%AI`}c-=+3zM zY8_|YZRAr=0dCX%zRcfksE@Gow`EHR8Fp^`sZ*iWLthb)Ui)o?7$;;wB#SD`_gRqP z5~zw_V)&kXezwQ;_B!$h_iKt-xDCSi@OFGGqhSdjN3Fin_uNb8wQy4r3s4Fzm9%Z3 zBeGYvK_QHnO6^DURV{-GcQ`ZVn4{E273cl$+W_vb5ireU)O4jtfdY9n~aB#L{Y7 zc~?7?u?Q3pVho;e1qv*}m1<+r7E4yk_Sv;h*0u&b*pwXG@ELI|Ua%Nb0M%a8er0?( z{B^E!Em2*o1HHv1or~)j-I($#&1fB^0ad$R;AP6eYw<({kBI@FNLMbuPB5!*fe>^d zED`@&ck@No#metdhH#4vM?+W5W#N7d`~SWI3i7erY3Gk_94MS7t}B&7&7>G!W!=ka@wm>g z{*?`WX`<7d%&zudOAP`3UkC$0_L=7f z?P;7>E+7C1!K8^7U6AnI@i{zKX!dpbBPajD>ecNp{~J0GwtpJ$Btme`|NCj9HGo3{ zA+&J{6yU%;8@BaG0&OIaB>f z8i7aRE}5t~eJ`N4>n#nFq;8e=DSLXi_2ew|-m7RgwMC`!*hAZi&^p&GJa>6&Pf5*9 zo*+;`nvzS{tAJ-ZPzWtc#eYZI_i(;IzE!qxrbXAeZLQLxW!GsZAFl?RiEFpw*=QCv zZQ)t~+_TOYUv6t|`=c*~fqHRFe86qPEc||&(r&LlPYpPTpc^btc|BFn{k$$0odjB3lF`$b*Q3IH_xBNUPyU@Xxh>$tElu znLAh%PB#cjWqEa3H_SHyjU&L`>wvbc=cDHkVc-jk!F?rj{oO0*OM2Ip4{Pg7`GpCO zZh!UsBg8Nb5!>{i4*ym9Km|YqZgara8x{+3y5)0NHr#tMk@}{b$WQks@X_W@#d1CE zn(+9ppLS49uam24^^$S3e|A~fSKr>zQxY&Zvto*{NZTHnm)N#_D)UQl! z9USX9+`JN|=$0$J-@ICL&Gpfmf1z|L4EMlMFGeh7jN zx>md?D|5Z)wk7 zrxZLQj;|Xq5|B_?5;~VmRU+PR*dZPGL((W!C*GeGb24~r7)%}NbHm4|_)1T?*gWg< z^t>km7y_sQ^cwQV8uN?%;G-LE9rZ2$w}fN+_|3b2^7@w; z@~JR64xbN7hNu|q0j9I}`{`6_b9U=)T!mpQuwthVK0N-VnOpC^+ksJh+Whr#jT<4> zEBD@)#j9EV-b{||(=&vufgKs-(#}P*FEgYuBJ1|(8Je|% zqy@)r)oNQOREdM_=# zg@AvZ*z$ZBJa~8XdOT+f?WW28G=SZmms_~Wx6Q;g7uobA|B62Svu{MV^N6%O9WnQ- z6=f~)y+9Hj&Wq&p;~8>Bmx?w0QE77&o`Zs{DlQ@Xpm zJ7)lAV8(aeZ};;r%F<1)HoLU>Jz-Qj7te40rPLO;+$!POM*HVl&KOS7(q+ z-z+=(X3R-PK(+3kPF~f6uxI+dU{~hp{0s%yxMX2#p7*6$HFl&@``yM^NJRp-satt| zblxB&xTvLHS6Obl|Ng5?qO!ZZMUuUCTVv8#z)QimhIF$wwGgMZ7OTds*&b_MF6v4p zT-!Moo-0aby6Q7E+qqhTc;t{;IVXNGqDaAQpQgLF09_oglvfPPoj{QFv+kxdnWV4Q zSs@r-wz#9xk-tG8$W)urD^K}%Pm#@&t`^B4ZIlZReuh-T>KP3yK|8UNGA%T<2Dpm2 z58P;&9Pq32c(>d*z}UJJ#z*X$@^oP3Q)T6wA9rbDXA1%ds12dhodKNf@hS2Cnh;O9 zjW)9{uv>~96|lz4f0+V)^wS=!*ooy7FOP5wo~IfHeJ@{oP$6<)!2{{yylZ@Wcq!%v z!O1&Hz_lnT)NrrqdwXvZ(+y!b*T^8=yL6?OzrM-FGRffymL+{RbU^-)a~N?f@6xUI z;gNNWhBRMdMgRJj?SEx}rZm=LJL|%<8X<|b)8uyTQ`vMD2YJwtMwu+8Z-{JZugWh& zcghacPiv~bv9Q?jbk_L`(z52RrBFb8qc02)*BGDC<-SVzTC_0T%MsvsHV*pr9BURZ zju>3Q5BJwOM%|R|5gFPHwEMpwr}}^xpw=@!PCJk#laF-KF>tyq#{@zJ&F*A z0wz6_P{emjrxA*7mzT>a<2eDGJp zZKnny<%Od;_rjlS&l>K=>E@k$I^Qlf?cBPw>`qIzXeGjs#NVh-N>xkG@spd^6ucV~ zH+p17K$q9UiUUY8c+IKA)nOD^W@%2_Ndx$8@v007OP;Amoo?cCV%pC}hC@lBvXhL< zWLtNyiFcU3E{I0+@kM26oj6exE?B&4KYPp#%zIv8K(rPBqzUsL*iaNh@q2xnCKdtd z`a!PiFFYShJz2|CizJ7&?GBE~>9lLa8_u+gw0uex_*6li6#m@vaI0f`yLqp`eMVjd zDw?+N?mi{%p_Gr;pz}d5WBJaF?K}LwCUfb}@;2ajbV}BQQtAiuD@NC!rC&fHW~)wt zKN*|0oA9$iZ7B;V38z$p5VjPND)qmRAP|nS#WpI z^Mlgmi^x9&ZT1`Ib(0*E$=f?dm{;&*i~Y7f8*k>j@5}W|Uq%?>EQ&o9QyJ@^p7)-n zHM}-!@HU^NSLtMzg-%tY2Jz!i)3eaK2}`Fy$fm($;g!LF;X#q}$~RTF&Y_XQw3d&E zdZFUuq4)tcvLOLxNjR5wRI;0%;rS~T(G%{M+R%ofv4@-HYr5_P+{g}yy>ziDIJIjW zJ;+f@pk(u6o!9QVYCUXel%)HdFrk^Hw+Iy5DAV;uG2E%^G5>^j&=0?${mwpBUwl!= zzo!Dswik}cVN-vXOB?VrIQ;z+k;Js}i^(uohDQ&|cfql9+9MsCPgfcFjWw|0^IcWS z*{UjE^NdL(bN{D*2-FElnjY8X^Ayz}@!jcv2m{X3)H|Rjj@d8o<^bQ_HsmxUS51vu zXdHPL2$=V!l+geZpIn?$zNH1Xa!bFptfE8Pl?(dyVh7(7^>Oe2D{Mr4t^(AF35ZJ8 z`7^-hglwIx{^IAnMkCkoA+O>pWci1xQ4*Y1kxY+HU=hPv{Pl~tV-W3c$K~JC|J4MA z>+e6_w63RNTVcArKb0y|z*z72M5oY{6-`}2l$BUtM{7QCqgug^AIb@Ll|_HRll?Om zqU^0-|FLPctV?DgShLTNhfFh}h{@QS@|M+pm@>E9Z*@f`oDcStO7UQ;kzE?qko_pD{ zAg^Na6OVJiJ?*$y+62DSa`VO2@p`krM1?5|&tV)&-3X_prlM~TsS=goW(6h5^v{vIbSsLk~|8_7k zIp&yY9uZOM7%fXFy9Z6 zN9_IKV>(4P#Nj!bt=BsVXm=xpD1HHR5rxlkMsHeb6UAR)YY$>cRpqR}*|WHPc7nn+ z%*43$eh6aW!k4v9Fp<~5;lR8SaJdN70~%2UE{4F(xoYenS7>h?EHIc?te+jc6)fl} zrfJ|a#DPniUTrX3DOZc>%I1(kwPGLVC2YPz^ERYcDP(~?TMBd`W25n$GwE?*v$!JZ zRw6Jjsd|7{-z%szmLHfL-MKOHuKDbfD;Z?6YMp5rk%W=u@Z-!CENo-ceEF+mp^{V& z!3G{i=rdD;f%DlI?hMBC*^^PZ3T3hy8|g@z(#TJnXGJTWohI+nqy89v`D*=Va@#w} zYS0Amqyr!!WDUVic|rgOIpC;Brmb3UTo=06oK)44(9NJY=8rTQ#HZ43n}y{s7Ugsr zPC=7Qg>X{Dt7X&WbJvQ%^m4zPKZdDyLSl@_;mi~MLZg{5KjsD1N{1`s$gLign_W%c z+q+TleV4D zL`p>CwSBoRbSrB1dUZ#D%5T?d5k&VuuZ-le>1qoUjYGp9UqoFUcl%T)DtrX~5SZ0( zi@HOITnTqxk|-#c2=4iejsLeVP@Xfsp?%B#A(GmHy-wkRba5-52+radqhaqwK+nBe zzgZi&Pih|t27mqOLc#MkW{b3C;8>%7yD4Mkq~#gQXL`= zhj(wo6zAB?xb232pYf%`H$3FsnTDAK*-o8Gtjw>DB{7-|vTE-AyO5`=anYn-tOQ9S z&=1=k>D<3f7$;d&oZLB5ax>8-s2pOAT?vuDWO_LY-YvUzs1zbL82TZjUh+cVl{e@Z z6(=Yjok&AsmBE)MiOM(az#|$bn_$~PY(uA9h&K4sEbeUmpuDzx&`Q9P_cHCzpJmaS zTJNaG2^X~9f=3$gXeRJ$#ES>29mu(S@Hmasx=MuROzgV@EC3E$BDt@dzwNrl!Z=wR z@y{3WShyPTND%ikU+4-<&WhUiMe)qlWR}bf(JI%Lj;UHATkj#PShD45e_dv_YAbN? zbJ|P>GYt9U5C{gR1u&lKpYpmsyM-3=A{cm?BS_%wnK*afu9CanChh@u$EZ)TgJ`fR z(vTM#`lbKp={L!UD1fb4p>c!+UVMncK?4N!@+F+AQ%RBRjg|;5;$&P4YZkuLNho-J zO`p3zf28&bxC)uBD@rN>UKXrwhfP~RhtCA%3)Ihp9Pcd^4RMJ^PufBqV7>FMMmeAt ztp`;2%K+A+9jv?g9|DJuHFy*DPV5I@fb7|68T|*a7F{Ow+%0)M;wZ#ZaD#OSMbsUI zr&?rbuEtB_i3GRvPH%jru0tF0U|t)DuD`dGR*kI|5UQdHjyelHDHIzmx%-`88hCQh z-XOnOUK6qU^kjyDgz$ScXP(3JSF-s^xL$J?t2x{3Clab>m!EeQAiu=opp;$9kZIsV z2@0Ej{`1+c+`Z)QRZlD}$jiE*bB-8wFkZK#=TrWzNtqP0&bUp0V`l}EfV1+8&ML{; zR08hgMd%xC=BuH^iWc;ipwfID7Qyr~G2vPdnf}M(9QNA4sNd98yEfEkuXB%!O?LYB_eeG78dlDB1rb2Ac_Mopa-MkU7~dtCE)VJFDo@`IY^3x>Pu%?rJbfkCYf2*#jl!j2_zS#aeN>TVggBZ} zsQA;_U-iWL-eaauTwH&0&wran3oj zAbZLZ9_${ZE^rwgSbikuZC)5yG%Q{By?TPJC4~ z5$aQ3lv=64Jv`^mh&<7l%pa*BhGr4X9z;H?KWo(bUJ<0UGqCL%770q^Kf|huLtG=% zYuAzC)}VuI+N)JT)>;$htX=*bdBcN919DL6uR)4-8xqUAuCQu+^gz$wvbzASoc0S; zTjHZ0e*;F7TGZ;3g!miY5}P4wahXrb7YuK4Ma}YG&Rt4~cJNZO{3~ zW&l4<`9LL%yv1l6T4omejasS6b(Jpoh+j;T^7ZDvg>PSH;<7guiVTvq2KW74-20JV z^VHLa`RCwlHEG|cM-GQy0mN3EegH;Ril>UFwRvpxIoTHJbbvT^9TQRvxnUyn?Ji`X z9U>*Ki|QK>}6geAHLScQ}Su5y=F6Drz20Y zKam7i%$voz{jYxjcRNH(D z?%eAJIrcs<^OT6w+8Lyr+~M?W7ptuSu+KW^rL^+B0@T!RS8tp3r6=zN6PcBBO}NH4 z=4$VLx{wN2Z?xcgTtvOMudmB-9OV6D$Ja$?FKjP2Pltj-5|h3#Y3G*$Vsd5060gT= z+E|-<81Pca+ELKu^=lB-zYQvo8t49N73Vs4^~ z&APj=t`_7JDJZZ0$HNHwZNk~%vz+l=#?e27Eat~-w%}@ie%qPu_h82T=+i1Oaj)DA z1O&eYl8lGPGLb07@3N~FUaCB6UUr2Bq}lf_uH ztvG;?Hpbbowg{NrFbT|BCX2`@8lJX0RT--O(7Y94>3i>}Bc8nolv)gTeQuH))%<== zirW$43Y6`Ut}b4XS?w2dZKV`oYRO(8qLn#+n#>}3@>JZP<7Lm*?$l0D=XMU4sCK7* zuYLKWlTzPvq9{)n`o7`>=23aR@n_lwO5UVbP;%fC?yR`;h}C?NYmeW5?yr=o%^tSe z+#_$Lrc_|{u3egF$+zS>n^J%g3F5(fs9TLmg5vz6D`MpxftK$^;Mw@)T z#s9-cDip%lGsUT#om3Z91wOPi#b(qPiXK}z#G^G7>v>?(`Hzhi9v6=VKd)+&vBo5< z!+fUuRvr|2jwi`M`#-7Rc;5FZ7Kj*`1px-?hp)F$O<$~7h`Av9BAX5_{}qL_sl_lD z_FLK_cjuo@=Km0UPlTF?XjWPHQ5d*md&u77oGQLY?duC7ra|E-qpt?j69IU?*IxGl zMC*%m0uwGFDnBZXv(|;dM-+jd>kUTwbp&Rt zF48ZIrL>ql2HZ+Qt?@5|DpbA{&$fItQ%YXmR?I^zV<8X&mFm zhxl=T2t*H_F*0i39GLrU4CrIxm6%DR=L*YSDzzbr2s2AiuaHh%(zB*HCaQJ5AwFX?om#Rye4O|q( zDWxFMUI?e~GuJuTI?z4eCuM*F`+k@NGtO!Dwcvn-7+OBBc81qP5_g^`sYFg{ScB7P z6wiSmz-%<8<>AXbbdT5BlObQ++n`YHvtP8 zEt@&E=R*suV8?8R%r$_pj*ZWd_`l>PY&WM@8QI860ri)@r9(yom%m!1F5 zJ;Bp;-I%bjR}mUE<++f=de1Px%2!0xGTDsNxxsxn;tze4VIFl%mV1$*eqDd7p`^7b z8ZousnOk}6vBb5X%wT=u4arQ6UtWQC(I&I6wiofbd+GR3E z2-Fi6BBp2x3kXsR(g(*^-;KX9_Pej6wA_Kdcb#_i@ty?Wv3LoL4#D@)+s<<+48p!o z3|iL{1bj3tbbl=?JpaRi(CqeXnZ*)2z{4_lQ`xD%ztY@e(Q5u{8ABXMdCGqZ6P~gm zc)Qh)u?0`D*1K+Z1ydcpgK{i^ujFoj)j&N@VWSb{qF>zpD-k*whuHMhcURtuJ;5^B zSbd2Q9MH}{e?WNiPt)I+t_GOmTc<@IIF7!XIi*w=DXy6gHW17RwWII$=?7{g%{=#2 z-c!yt^)@ZON*&aOfmmi^y1|_{qHuKY!&BrXRlalF?d-;^=T5NNKZHhh5HjqSF#KK+ zEU+8ZH--Ap1=c8rAZa_;-5N|g8cZLl`m)BwA!!+xY8GQHv|fe>waTtZyGS7F6)YQf z316A6C}B=f0}#upWN4MU(vX*)4cfn315CKCepvRt{N5k5Aej za4TmM8!%MbP;;9ST)z!u;4NOdxG}lnCF^VnSUOpOo%soT{G_JE>{XKS$i zdzAE8KgZnM-@2{;;5K0Q5)Jky%_`RKm4YY^_%2~te`%4P&gWG%dSvm<0JDak7FJ2%~ zP()Z&((CPO$m`>%jFf=L*6f5RKOD4`b>_t#@T63oAZ7-*?3C}P2!kp--vfkw0HaG8 z@te*BYM_Z8zqlwX6V}#)k8<7Gqnv+GrzEPij8}QAfSpt0k7Um`IVGns*4NhuM;0xr z+A8_`g<~vS{B-No?<%vQWxB@U>c6QPVM_aHg#7XrvIG|Iez{Z-M^n#$NAnc4Wndz*mbjdvl%QEI8b#Dw+hQ30t<3m zFzllCstTG!C{u$xP@&{Ya4&@z(OsN@IlxS&XZIxz5*Gx@0G+~q1TWnXzP1OmQbz91 zcmpl>u(bU0+d{ObSIo8W#Q3IQM;x%?q>oam{eBc9F&yPP@q9 zz>w;4RU7E6SAL5#;9Hzhft^U58)Hc z(RcsXcV!2fp#PJ+No(4K9A z#P)t}KUTi1z`@nQocBjOn$&`4k}M5?6Sn zfi~;w>Nh*Szpn3bVh0NZ>o*|POGAU`#FH4=sv{UV7;?n+^MXYvJdf(7=BqdOf}FKf zS6_n7f7Jba$HdtM-gs2#(t;Q3Q*ESrtK5v+1TC~c10(tnKQv)wbhDYzttQ#Hr+lXR zN9#Fve~bGZwYe_HV7T{-)5&t9;(Ke0xD40UsW`S#dVnE&PzSM(kKZGMNO4%3vrtIx zDFXn$JNzbw+bI>ZQuE_cxnQ0JyVf}OI3eTS%aV8AXTGmlv5kg)zfUyj9fnnGyCRM~ zD@=XD33zT$1x#C0u(Ut!YtRb4@H7v6r}IO!IV2zE#d7nn_N?5Ot^IwL8ghLis(wGh z`RoSL3KN+r%%I7bH)?IlIo0p0he}E@l-f}&KISi|hyh3A0`9YZOu1E9@xDir=k}=H z#eY`G3{ff!k7N6XP__BHe(i_m6|6vUBH;d{TQrA_oJ>LCp?o}oiIVZxw*1Yvwf)ZQ zOKgorO6x;-5ps0Jk^B#XR|l979kt}mkab2C!J;0T7)9kgIAnyxQxcE-R>0*mbrW}c zvV#@UsvQCR^GCyoaM*)Pco#Sam7F*CiTkUZCRQ4!H|!J5WYsZM0NB3!B>>EW=|zuN4(N8G3WCsvMp?~KIx)0H>RL^RxJB#nj+ z2yU^Hd4y64l5c``LD?{CMI5mh{5c>;3AAc%AiF1}Ts^N?K zJ|e38O5fvy&}{Rh<5{dO$AOSV6UGdqjHeMtqW<1@&Df__cm4I+xlejGA0Gnvd0uK9 zEGh)(*hb6sF0vfm)`Q%NwaiRLYW%!%y=qge=IS;yCyYK@X74`m7O3<|PrGHmV>6DA zCCFnaXe^!dlS-5gpf@%ewB9x;J4#df>bS%sGN?e8c1UJa<0BU>tP+*iXMg+?+3x%6 z!LN1eVfW4#T=UxRpv|&P_>V4e>sJrp_Te8QLb0J+;A_%AKO>QDH~Y&#C1TdYf2LgL z=h&4v@04-3uFacvBx>`Zj3|R;?9-iLRp@y`nYLtgDuO&Nrh|bIYuLuIaq%s}Y&ha5 z>c5hpU~554)`7cSk^9MI$D`aumPq{r2eq^M^zsFLkP0u3g6>sp*y=~Cz!RtySS8FA zEs>=CCb*<`;q%vZlC}h4lkZPqqBa#5Pg@TJk=gr%3Hm3&ad2;S-U>*)hI>ezUF^sB-HjvrG#U8LdR6=8pz43mArV2`=Pn zp=!~{EW>bGnvPtDtzy#KTdz2+7u!68x5|NT>8$(9Ff_epgW^G?_i4^ud028-mK}pL zc68S+O-$I1a*FL_W=;Bp_~3`2`dR5HsLjudCx3l`fDHK}9nrOB)(mUz)bDBA%w{b= zW^CRh?AB5}kOhb|p3^#neOSB*=dn*E(GZfW@QgOe^6PWMNZRi?hn!aTNOWR7j1W661N2s-Ua?Ozt_c^!%z<+?kdA?+X~0s@`X)2Q z_iAY*6{y#g}J(vS>F__z?%JIA9)_-(;ABgD1*Daan739)sK{g|#fK zMZZ1BiV^>!9q0XMGfYz!E|n(~LXPJjNp^Y^KOB=Ta~nI7@Hk`i-y%?ap0|NE(uJiQ z$Y+sRRMt*-@F*;7G_GG1zC${Zqy3eUJ*oBmr%$rR;pudb_Io6a)wqPU-Ukr2qqAK% z_;8Zl`6*Yq)0m@LWcB?YcGA&|e+XE@Ga5Q8w)oVdA<$Gzopf^?c);Uf#x%or|Z%I~-T@$kur?(xCEE z;2QENUfMhy7pgx4OJXIi7+t+(t{Hj2mJXCEF?J|DzhVk%Ge8{9WDMIIW3gb93=+GASsfwnH zp{!g9)Ut3| zabd?~Jx|x(z-qd?t(e5cFQ`p$Mr< z?N`?uvLk*Cs}6LD)1hoJ^gJCwYjx1+nRVymM2_e^l&0;k4lqS3`o-pEGm+W5r-Q82n2x5C6V%g`WnJ~`lEiaRqeHiDgot#U zQ26I?@Z)qo*cPl`v}pR3aSYYDvo3NcIC=5Puk5#nwB)fLrG9k-+dB^4dgm?Bd!ngZ z&Z?Z{<^{yVgz}T-7uhcR**l2ms$Jg@&ME#xj@Rb+dC&6wD}9L7dJ7@rJP$N_M3_e{ zm29N!t7M0(cICh)hgO;Lfh6)e`K=F{u3Py%^v5;Ekycs$1{sBM$7{z<>m_TS5HYCd z={xb_M#k2}wIF8;w3o!%o?St4FBVuC-Dz3VNoRmXtj&ag6*0a(zIuDnB-Mx6==uen z>KyUC?y*m0yyi1feSQ>B?J>lh`71{@;K3gyL-d`EVi5fE-*s#pt5;@$%ZEjc#_c6Uze0GtW#pSFI4OTDftAF;Pin?{{Rh^r>c{I& z?}<78+X=EVwyR7B_tlq6Sgy~75PJ=-bq>cC{(UIdL0#WK75a5gPXeJ}6e7z!rPZyk)$&IR zc03Qc4>(vk*7sNGe_ZVor#-m5!UHS7i|ox;gzp+1po>G>H-+xMHtK4ZnUV~{NxP6M zQn6i7MzUQpu!+*Fng#T0xNVjkd7~2#XhU_#8wK*Ml32WC2qxXblg-UrSmURrLg#>6 ztvzlFMl&`VE#xu~pW;(wb^Bo_?L|&T0ml#V2|k%$gs~Dw@cVYGmYZt+22Q*HMW%o6 z+{W`HYY-IShn^=n-DIdD_Na4R4hn_{g#`(~=)i2FWu7O_nBazK2HlfN-S{o9I*5Ph zka3#`zE1co|3lxmTA6wqolDm=!{1tE2G-WFz}l=;Wu6JArtD~bdtw7;?FF>{x92;f zly&?0V)rI_K&HfT_22KKIR8=;B_9Hb@t-vN8j1r_iz*+MeEuN_LZ-ZN{;L2Rh0%e3 zZ)QlwfVgIa(Y)u$7Av*`1HP)m2SKwy+Y<$^pr-ElC={(~E%JT9EZLytwn53yjPu!z;4`U529243 zaWD`(8a=@*Usa81dA#xKEU7$=RIa#I$YXg-yP8^R^~Zy(L*3hmf`EF}dlH!foh1j} ztKKGurna}zQ_rY?>-?Oq1$TYW$HnHaKRQ91;Ze3Rg>$g;=dt~M7G8e|V^q8TI&nAZB!XQ5J0 z(b=RY;n@wz#gM1+6@0z8bmit_6%wv=wP@FUHx;LcZ`boEGef%UtU2{nxXHe}DZqzr z^;?rT#&-6ep(Ru3hwX#ar(U}Che;#nh>;~GYFW)o`j%RsR@>;Ma&PVGHIb;RK(1nf zg42RemVL#Pi}0YgYv)<^)4_YG8NY~Gthe_n88XHqaJPlU(#d<>TD}2Lx%`<9SoI|P z>T_kv%=*O6Q(SDF!V!R<+rK?#P%?M^YI)+OuF6FGJAaF;aCQ%|3VI;HWHD^kIm!*sm|@Ja^*8q@(tq_JrSrRhHOUWIT_R=O zndlG`8oT(n!YAghbY=`hc%NAet{TJ{n8=ecgKiW7dZ$uxiY*wC=fR5w#!e-|k8tOJ zHXO?n1wBfK!Gm09aKSRKQ15TEuN{d=^B!h`kL>-FS?!O53!T^eTrDptPot0Ks}Q>2 zF_U~zqXY|}mr(^Ah{SZ_mD0k*^HMDUReI@7a-%|z`u1!@=+VTW51yfGN+C$>qnGP<%%7@I z^Xh#BM-B@mi&2|)SfWd%FiiV&k#u%j4Hdt&?vPE~1w7am@$7i?)E&x=yd zW{_~cV1e>E5~^!zGJJYB{dx`NTl{TB5nLn6Mt^<%cQ?xOi8N9%LRPf|$P*aUiuIDfGb zlX$jfIYWvr`S$d}>0Wrt{>Vs1A|QLohSwNp0^~b#icLE*WY+;e?}h2*&xlwG6`J5p z{!5GJbb$mBNEq~U(DtqvBm8_V7|%rkpF55w2*CWo<^a7HYo$t*&NKD14u?3aJyiAy zCN*hQaWM}njYo43SJ*sluY?iwnyrPvtK(tq)dDlBHp% zahssena>&BYA1$eJ)GrNNHoJKOzb$tsKn?Nb@XGV>FpQ3eD+(j=J7xO{8u#8n=kfP zX=dt)VzesKGC)&APH|Y)c{nO>rf?m68mv1nrm3jV7DbvI|f=RoE`%(d+IeQSriSOMHlg{JQGDd&Z=4BQ>KP2SN#W6==DI$ zAp{!FhOp@iO8R6@`__O8)hedlk~8E14H|t+9rx(aGzzj!PEP!!WGtc>6Ox^R%1gp8 zzDfwA&B3~X2j=}^nY;O5>|o6o4JA0YbAMvA1iD;y0-9WzCn!Em6l`r25}UMXkkuN- z<|ipNX09Tx!v?LM>C}~i%g5W_7#RH~D^|VKst9+=pb?HiH7=KnqP9<>2|U6lb>I^D=OnyAB8J*uroVlW` z2(DKR{@6!-W>8lt(|@Kdl=_ zbKz-5)9s@YCNpeZHa<0j1$|C_V;qSC4@ z!qT5c`>c3NO7*Qek65Q1v!&bmv!%0EA*w3a!L;(&W$R_E zpug85OQYGQuB}?yB6$z$jSIpBl}df=)vL&4QL*%U1~|_t8E(wYHCP z6_0=PX5NQref4Wv)-N;P51zT8`-iZR6V4Vh{4kJex}UdrlLhmn%+G?{nz}#nD(Q7j ztLQyrH8^Dgk~t&^G?FSc3)OmE9;+SJ>db*xfAP?0VRzT9TiSrcJ>O{^x`)}sdyWyp znO=^;Tj`klq~H3k3i+2TB5aBn1JD1TrSu<#P@v=fii-N(uNXhn%Z4gH6gew51tQRR zVtS|WhZ0q%a8koU=(9`H7CN(_0>Wd}eu7O)t-ap70BmmD%OE^1G04Se=*+@-IsUPq$`2&76RF$8l;I{@tA`ekqQSeoE!Sm0E+k zG_|pzGd~sl1<0r9($A`fDMWGI&YX?W$DtF-wq2h>Q}(oMJ-u%`@zV;)2%_X>hmBi8 zQ#W$OnkM(Y9!cZQ{>cm7vxyhR~1drIPA!}B7 zuUY%%hvbNp{q`^tCMCu|$fUS<=3_wzK;Su?lNklrsV}`Oo!6!hs+C_39x=&nFY43x zyQ-C}+k#`M8NFXLf47)Ln$!&?F|>_MM-xx7O`qW|IlyQfb?miVF-bVa&`6Zy_0y8I z9E4aW3~g9Imr3UW$F|W=Sa4P@?g4i0&6SUc(r*>1s6URSiwSL5hk0Um8c6v!2D~f( z^YM%L1b$WcM9V{zNJ#lT_WGej4->`m!JJLoQfMhl>}`u#*0hHRwEw6e9z&Y_vTw;` zuJ$48H2wK2xd}$?YU34TKd9{Z!Mlq%h2Pvwo#@WB`nMXowjiZk%hN~er8z)k^MxLKNIFftSflq*p z$kC~8TY~xyJ{^j4r;LYj&n)u#M-rQ^)>aMHku&^f7J?>KNtL-9#5ct4_nD{kPa+K0 z7RYYlibv}@R$DcX0U8uhg&U*Vhx#4{?)9*MU%5wlWncGE`Qp=SeS_OzF;a+9elLTS%-#-J=ufNK6xR|mS^TCoHXlIwP2@IWw{ z&gqz$77;l&)Z>1Vd?~Qe;WYQ^t?x2mj(v^NfY01!qX+dCU=jA333G=dfT}xpiO2F3 z_o(Y7$G2oRqUay}2vbkGbK;3FWuoo3#Vdcc7;IMR)Q~8|79-c#=7)5xT)0lH(cN)n zQZIXZHP#Jtf6(YTbiSmY8aH9(+m!aBa8>?cb0zqq9f&@wK3qvSJ+hc*nP9_L_6Cg- z#q(BEKw;K?k>!-M%6b6Mx&G}^)Nhm`TTF4wF_k4g#kl4N$@Qe-5)VHxmYw)eu1ELi zkI#8jQq>ZZz11;4^^kgpc(s_t7mM{jaWS>p`(N}&ZSwR>v<6*_uRVim3)DtZL~L5u zPKDj(j?uooUn^ife~Sed zdB|S^dI3Uz2U*0<0;?|mW?wrsNCLXb4Y$k9Q=eEZLl&4yOrjBjy<-URfmB#Ss!dP_Jw?{@AcJ!_3KYx`jc4!3IW{E?qx2*uLBKV9vo?a{`kRJ|!Y~@Zu zNfaSSMriJ2(|_6rs0%l{gJ?jx5k{$g_MpjCVmRx#oAoeYtafo(XxoGq$m@3R)0-=- ziy_3*|9Y#p+{0)&`nu9%4&m-Q-g)zY;^#JUD9b)nHDI#AJI?!!tJ8Q*8eiCy#tZK)6~@R6ZDAkMC0`P))_pXs@L z!Mgf2>$kYr9PkHx1-GLy!`JTvYf)IOKk_AEwFelo0;Fi%E~uol=`e5#ho z?ZUs01a#uZk|XjIMROLP$y^d+TJq~HkE=JWtxoP4nsW-(>h~{x(r5QZoNuamu!K!e z7Y%ogBJseF&C4ZyQor<5*W#lj-tBm0orLHX{qoT;1Z0v(gEaS+ZjvS=cj>uF9-fbU zH6-}`vMMQ@)t4F-pap)J9IGp1_J0WOR|hSilc+MdxfCkB2xSFC4!bI*rD&~s5PNP^ z_(&F$w<{N0q=k98-BsZ?3VOAAiwsquw7gGb;-6feqaaWGxZQ*3QZxT&)bWLN!P5mh zMm08te=j^JlH$Zfc!KUl1H?aH#Nf1vjqZXFCVYJSbOQ@*UU7$8dF%RGH!9aGwF#7t zSkiXCo~=JIjJEgbKt(cra>lcei>&qLuS4gm`mgw!`Y*NCl8>d32$-ebNM{G+z^w^e zX8L@IHnws47bi5o3?CVTY+s*WAAr~N_0)R4C1^aA=_K+dPv%oXuVR>*@ ztQr`lhwG*UnRpa4gJ#$3JIqFU(!41xPH0l1{3$!{*Vg z!QbqV-Wl)3^v9|^i@WM_!JTY^wGQaUM@Tg^V3UKff=?q-I@G*9HGnWZv8-F1IOp_{ zJ75l}F}X0}#c5t?!Ac9X^>`((i*qnW#*)#M+A3DgP5sC9N!48RbgMm&Rp($IRu|EE#x%f{RBzK;D7Y#5P z#FVrk;zL3@WN9YrXh8a!fNs&9$%q<%)UYre?sg!oFcCQThzn|6&A)|hCj7D%#4kVw zX3#g+zSnF_Wwnkvy~R)sjJe%6$=cyx3dBF29T5|OIIn&Wkkxq9dBU3WMM|)K`5>3$ zic-;wci&UIl70~xSFOXXSu>?@cvzjnLhzLgoX%}pVOsNaTHS)4h-}q_K3ys8DOBqe zf;sEoz$e)JcCwVbR{IE-Ts_ifaTbw~PsS>Y#yulemI7c5l`^ONR>s+pSIJTczHaAE;f1+4Q!0 z%8uzZcH^{MuBQJgaKdR2UAqp>8 z!w3RON=m16cY}0?bf-`Kf=bSn7&OEOU z(?=1$Q2OHRxf8%_m*Loc*F}EeLXWj4ZCTcwE12Tjf@fTMZB&IBdoZ#lIbV;D59@E2 zM$*g<8P>&Su27LVm%!~xF&59rpVpYJnMwljZvw5Zhc$*m#oTM*{~>T(eP%Pweov`5?hc~SwJL-BvzCjax=}MQ$Ill%~yWWMOWBtxYh)e%FurjSuuI-)Dme5Q+&c6sQUN=GoPXxr5JUXSBL$KN93vH#MB7ds&JAmlh@cVQpHOd}QZwl8yb-p(6PYHb)p)-O$ z*)1HxHsIdnpkqTmH#lj-_HWXFXcx*o48=;Axjc&LX6tNXBnT@CXkSB!!+u1405nsN5kF8O{{*J zvq+o6tO5GDKJ(6J+0sOI*Awb!Xi~e@F0F>IYRM#kq9I|uK}!ye?Dy(+h|fxxhV6!z zGxOsuEv&)abG0F?=G%4d@F3GtSC%r|YDRDZIBS<8TeN6t(58x}LlK6$SIS>%!E?co zgjnSsFlShKxR z)5C%>+{MuT51(tMbX{D)JbQMop0X)>2Msya$IG5A|8!5=R^x`u2#nNzZUg;QT_jrO|uHSav~}C((sK*cEkM zliQNJ**h;zb^{AWcMh@qZZY%|1<@Z)tYtAzB>M>5T`c?Z!bxTEm$1M5dew0 z>+StQahRW00Ir|?wR1mMQpj(Bnzd2325`h))mE0$>H)R-S^%g6T78P@TV4*C^4D{3 z_+51jo>F$1>EXq9V^_W0D`InIEOQc)!O&)zmO~BEiM>#Xr!L8vL2@KIb&^?82+r7XTEeclsy~zlD#;H+zw!TdqGBb&2; zalEAmb2jc;Z_xVwDYrT$lJ3^zJ-c~6;`$ra{jj>PlTiy%V>;!5|j)iX`qO9J!Y?c~IL)sZ2zuvySLi+8XmdX7^ zxvVec*nBoz3@2~;+(~OKm=EP+e^bl@lE(C46;{qIQq;wd0{#v6K8YUJ!y)oBagPFE zN;g+NEpd>ig>A#vDuWfP4))JPOKp|*Ito&bJOI82#p8#V=qIGl{W#_G1a0H5Fb*Hr zaH#pnSc=f?0S|_8DZ|SefbED4mFw!|qcQ~fVl2_!J^T+z8s=48zi8Rr&Yxgfc3wJ; zD(O`p%YWa1ftBuV`FgKCTRN5B4d6NRZ8&cVX(DQ528CMi0EIu#OQI!2=eH_Roqp7Wh*y~G}#MO8-NX|5-R*b z?H>NgKU>j(*H@tD>Z452(->U%`xB(elFt7SoQx#>Ls82GhJUlVwdVb1%5~48cMSQy zSfT5=AwXJpT396B?KxE-GWc2;zf}WKz4PGraF^Bz504eiiDcWdrda04n0{ryH@_Nl zCrAi;kZUeS`=L*?vH!+$j^!zcAnw$12C%!MzD2c22Dr2RbMO^Sv9qXn4MTTRwyBN3 z%Z}Ihj&qlen{)Y7B4+1|fq^+;;s#Y*TaLQVn$Jep(XzWorh^-fMAqVs>bkC7geo@6 z&Q1E?v7#8G3dYd!hi1~RIw5Da1Frt&v#ueX59rjhYDde@A?J}VUqXEJydUoaqrabgZrN9omKI0T$;+*De0>b3+t_n*;nRiyxozDi*rpv%s#*Q>v+{?6mqPxM~ro6XRO zPP{?f9gPi=&FaMjPhw$H-d?~THV1-%FM!sxop9G2{EJuj@cfQLxn@No&2`siJaVbx z-(5yUnzfo}qd5GxeqI>rshwgYlp0&2teq9wAQx!AC8BdJd z+ODA(TQ0Na1E}3FkWC|jk1`(S5D)4`m48rvn5RN;!M#Wp-)h*Bc!JhES~*<7Uvy?wAPA(tRZqxlKP&+^&ke~)x^h==j z9Q>};EMY%arW1U*(G5V?8o)tA9yb0`^_%09qlKb!gVwGA=1{VEYjfeElChJRjzenQ zIoQ$W`te5qnh6_Vu=;>)4ly_HQ zPIh-S0lIX2u>eM8;qwDrh;uR2g7_PI;OB8&t^B)4HGgO)QbZFB?een)--bs6T_~VEX zZ~H?UsP)R}ZmCiH#plJ{TKS_c>hIo9S1F!=x7j&m|^`}6m7@kjWbS0osz6t6|~*A#^D#I$E$O7>z~GJ34p^J zFJp-Zg(A>_%7Hp$384Xst6+g`l6{8Rd$$}NMtO`Rr)oy?zbWY?S>ABH`iA?nj~e0u z&6$xs0rZb%znhdoQP8u*-46>%nLGwe>bO~W_M`t7#oLh3h}aFyZGRneXGh&Jn;pR4 z>4x*F>{wgFr@j#TXr;(vJ>D4b5C1y4{x|+LNm>d$d^>m{V5sd(95%`79IEM#@s~5) zz+7tgrt+bN*$$LCPBW`#y=Nw|+yL68)BU`ol0FFJzO_bM60G@o5Er0ahuQR@c>ZMM z(y+h$(AXDdHbb&p7mjzc+}Vyp(!W7DTp&2kEHvVAY5xe0EY)=*>mMv9!xakKnKqj0 z=30ZxJ`M(WlW_g?;>vOy28C6e9n``ZW1L%}Ux!c-)zrNRJ<~N}(nKsp z7hS<_*Kyy8JN$P?K9P~MZ8!RE;!Yy5Pt|si4w8&;owAtp4QS8Qu&E@QH71=T#;y3U z2Nx*JoxerahAuQ3l4kScsB|C8Iqt?j*MSaR-DMwKM1HoHp6~~3+HG#w&?VF`H#l()XW7&m-&jp4)|ZiEj{kFt(e}!ljYUp_H5fmsBpK&U-?92 ztvcmi6V<`G(GI)JqPEZ9oYEpdLvaLG%Vl;Wqi-TV4_#&jOFmEzSQfBWKla`-T&pua z1w2JpxSF;}r0fP^H)uz9|7uoKiKhKKRC0{tb8dXt_N0~^G|&9gMTs4Hn5)WzG)a>0 z(mI*VFDBfI0c;pjNO?3Uc-(X2N)f`AN%mf1L#!@gCbCTq5`p9d*~S|bVy=$KCR%uH z5H-BQRNcGp|DU;-oh4lm$6UX`+*ioKKAsc4frfH{^q;4Cybh`T@0ziMQ3OW>)|-{9 zuWP8KV>$4cx}Vcly=ne0wZ4K%y&8xn^B*wM-|HXN8&=7!ap3OU(~gMaAssc&g{q!E zIzM2Z8+BmADzk#d_Q@=V1GGyNp}_?(h^tTD=Vfm}{{GeYn&cP+ znGrUxUJ+-g5R!(@euEl>(}(>YfW}8Oz!#!`>C=#oPyOxnE6mx>DzPwbWWA_yv0DyU zCWqy<&7KCO+#g$=+JcGl;VF-t*H5j=`VGrg@PP`6+ICf3g_z5uRJ~n6>N@Jzwk*H0 z19+)`qPOuZhn4l(*L{DlQ>ihz$r!ukBB3^un1G(h874M$J1Z@PNn*W&%Q8bto!^RF zjLshQy6>K+ROV13e>$F##}VDcv|?K76Fxr@Kh#$HNne`59`mg<%XZrzg(L}t=fIC4 zPT@sH5|)pqb%x%j%+2Xp{|i^q=|A)F!*5Ep2Hfz5rdWv=fB3iJH)MPd=E0#B z6820naBnP)>Vc=)N#yAkrHY8`;p*Z>{3fPTD>MG?QdmJ*gvV3wxB_W;vi;tU_V;SD z4~YidrhmXF#XeCk%F+|_F}T~mRjAXU-|1;_8Zi5Cf21te+vL{vt0`uTrla@us8KZhJ9Uhep?=hRjXq$8_XWZ!EJZz?^cLDMX zo}O<=ToScmXGZqRPM=>hQ{_NgaPLf*4rtQ_#MP~AB%EnF*%@hGgFShOZ+1^iv<_!k zHpTQS5h#@!Hin1Us;saHZ6OsHw)e^yWT6`eP}OeU$%(1-Lp@sZDmsZ$CZt(t(Czq( z`TTEVmx5B0ZRbgfk>~iKo3<3Q40eXdF@KuE9N_x$=f15!Y6pv-GuWlyut@IUX1T4h zm-LN%?tIkp#Qu4@U9(-Am4|o50xLx4R55>53W(!4KTucIfA0&(XH={;P_Qf_=be)) z*=PfH{N_)TsX#|Vt`&=E)<`g%z#>@c3SVVlCCA{ZMcTY|_(A{oEOb6u&9d-kXs(}; z_BsAtBV|ycJshuBtX+p?fqw8$%!>PZoJ20kzd11HI5L~%(q9JvFcYB-FBI?_${?T@ z!}3U6#&B_lK7ZCnpZ_c2a1(m0-o^{WbLRWzpXVI)>muq6<+Tm{L2+?Xy-~Zu-3a{@ z2YLBsgFYv@r|ad|KA-OmDIB{m-u0&3aTxi3*G`?qBn~LYU56=WNL~{C=oqtfYTRUb zvm}ewy-9VX*<;E!kq)lkqzaO+-WTs0u+O*T=qx+TMOt55k&15%kd1yieJHBi8MtZA z)|pVpG=B60d2bTrwUXl1o%(XFstM&cyUaQ9)!mUt+^8@r6dePP#A88BKR1F+Z`FRm za?e1HA3j3dkbm~b0Do=q+Hf03_Xe)iEuG|wvos$?dR&ss^syjJIE#SW&4!vMcNaGE zrX^u9_I* zjg(~rT@&!^E|*2?)gp<`sjJgV}l>jLePsQza>i;ZBO8suMn zwOPGlhvz9$e{oug6L8TtM;ui4Sb2EfD`$(dNwxR9q=%%R_M1EbpVnYAT985(i>A}M zr4cDhgM|+)^H?(|>@v&!p709Xe=;G(NKtribvSm2+Tm`aXwLlBs&LM586%Ymv)Xks zRXSyNU&I7K+Ww}o<9YkEQFo;&nRR&at@X8otPOPuNM**R(X$bJs%MylDcgVO$d-}| z84X4jxH^Z8eSMy|IlzW&YlK9|T{Q%jKs&nIB&hB@N-g^ID}yohNd>!^fYHeo9dgq! zMMJ>WK<3=k5ehQ_%>!~?dXXTQ9MAR|^I)K09>uUNw+)TO_wjQ$AqyQ3eldMj_JqlB z2zY;gCB)ozj+AwBJUfkA#~vi?B@&Y2mbwuGZ4+ON*>->$uwSS0MF*R>V>h<3sI+wgkdt5U^{n=dJJvi7#VdpD{!512%jisdXRfoJupbs`sdE*w8ZQsk!+jc zx9p3*C;v3hPMg9gimC0Lv=0xC|AJE;NV~~j$aY6Nw!~bS6Vw}z5<-SRliynSfpXWA zJ_(hmc!$#=<)5nXQ%1+ZiNXi$xbN-=57tXq7GSE0?3=ey7+v@DZwS&*)0~$KmH}U& zY_!V~CH-+TqBZ9w`h#x5zubSbVJ|YroM)l3fO5*w(qNKH@j*b*S&cpyL4o}jlcU+? zd;uWO^8oa7M(9t<)C<~&WTB6E5MYyjzAV~k?f1K3Fzw&g9#F*YRcyX)qGLeDH)q$A zt=z^rdyj?=IeC$5RS&w!eXcWv*fz(2cM0HRlZyQ|%N+J(&sT?L<8~*#AAESi;XyF= z`UF&(^FZ!Zqii%R$uF4>x9tvBt)d=vU+X=xSacVqcMS47Ll&#Hd?u!k_=yng+n5O~ z9|5K;+3kWNsII;d%{mQ7=&WUSTVWj*FG3TIfoj=^F~FS*I38>1XD*lKDF%lYPn``+~&q3w>}_0t*}ms<~BHGHeElAYYg2NQVUCI z1pMSj1xu&2kcG-ECQHx0KP7wu`?kL7R$_^nFWPq$X)SBaf%}+ApT7tU?a6LQAKPdlJYhxlX>VgoR^SWqblg>&L<5ohXs9#DlP$N#(#ax>kmD zVTU)fpB)L3sr_$|erCmqmgY_7Fk;JK>;GLs6{2zY{?0mLf~1f7pN@bsAg3c)-X0<4 zinZi*(DICz9&P&GAy!YrmV#95SA`+Id7_sI6l_-1+x9xldUmugA!ZjSZg3!}M@8UI z|I(q{?7Aj0+ba3`N0nP~NQ2}QM7mv#LE=rP;kqno0eaVCb4V_MgnEC}v9#uhIwwji z%-C9NDLKUpjozE=z>DIh9L8ABzQ1D@E3^QW+Uii(eMkITa#bpmZQhI*NAZcVg}5Hn z)v~hpl&Cq&3~BTnyY*~&M`$J6s?8Wgf|UDtU^5%-x#aijEW6C&akGUE4YVMv6XK80 zhPJFYvA*QG!&7CL3AW-GW8PO8!nrUFE*M+5A*E9mwwbm)p^Q?P>DYd+!?P4ZbwS&26L?6ct-WJa4Tnr}v()Nb1=-1;T-8i_i-BpcRxYSB zk`9fLiKufW@Ri7>$d1Q@ZT*@S59!({jyb(IX?h_!1Sy65cM@Z(jjFK$nh%<8Xvqr$ zq-R7iGsR#2J?Z&t)g45arbrjDbj*Sa9&b5I*05qe{(6Povc{ASST$%9@qA!SRDSgf zXVD~v76vO^B&E{EO3@^gYKY#dL z@~UNRdw#T;gAK6W_hJsR1c2K?^1XizSJnx#em2)+*9R(XCfa)0!Sy+eotMCHyi`xre{^A|Gq-+q2T9-(mAM3f~ zim6de=Q`@po$(d$<1}fI%G!s?b`VRz#wAv(%O!^n73h~j4)vqUwB~BOwP;t=r8c0~ zKFe~bIEZSu+Rg7Iud=-FwCV4p(ME$k5GJyh8+oO8mZL5}QTfEE+8BX}C~VP7yBy#{ z@2ZIK4-0Jz)JE4aMM(a7BPI{C*Lc>&e+(Y!PG?}8M_pcd9{uplX~pJ<5>J$R6%ym| zhoW6u6dfwk-k;Vxgm1hhJ(3ASWD1HRu&?1csy1=#!yefxvwkfpZ%h)455KGU>?E=j z*tVv?R`5AcWzB#WZ5667CR5~^) zB=Zg^@6pJ-DWF-UmjV}Nao5(qbcMtl!px)sm1=iR8b9Yo#?d-4@8!$ zpBB7ZQ&3Y#%r4Hk3Jr()qGy{7Uwf|dGjpyLC`a$z-RN#DcP;Z&uLY;e@N8<0` z_nx3QM&{vZQaW^9u)=@R+so`(YsNh{fJ2OVNj3T=Gu*d3xCB2IR;8X)zRO~Ska43_jO<$W zEps{f3^0B>`T&Lh%*>~`vD*78XO7WG-e6F_7o+pLaFLHx!2#1Qr8%9s4oc<(5v8ti z5@uOF&_vjekXaW}l4Fzaa7cq;{CUZd>e+u-HJ-LNXR%^4((T$ZkQ4IrDb)3ua_wGy z(S99~clMz`md}wtoU>9eI>o7K3&D6ZSHURWgvH-jr{di zZbq1}5B{x>S&YAWK2SH)lIlLwldoi5_t6sO3$cY%7LI_q-ba@V9vxng`p7iw#8UD! z4g6c#RXCRpcfxiD%pTE3=o%y^y!$Qs+2y622?KP>#t`HTPZ44WtDPxZC93r>)CNlq z3}lm?itn}QB9wjEG?$obP=u_8TUFYK9|_`WGb2Cg#5ig6h3<6lI>x@*$%lM<$jaG_ z$l5t)wc(wNCmHQP{2pr9CZFR0$b8$mW;xoFQnmcLYDauXD*15d*k5uW8>@5rkujrs z4LOf6RD%@7Cb630jak!HPt_2>j;8r(Bo|l$$e3$$zFGcKEK;(*19FTyw^{PLnoWx} zLHRBrK4DIpW&%7x+S5Oyw@jo!t5l70Xy-+)Wy|DzpF{p1Lc$aw za1-27;%|c#8wLudYnZJ45{}1!(rbopTsOPiDe|YroEeUr^f4P!UxBcon_uNEix4n^ z*dzC%$1{qs0^~f4s!gBu{M-njK&nihJwKTeJDy~ZRKIuXo~*G23F)oF;LP9b!+C_s zHnElnD^bP}(?Q8=uTah{=!?TIE7LRS)*NlqXv9W^wv~giuvJH)VmR6^CCjzLkz+X3 z5ax0I7oLlClvVb6<>TK9I@;Jg72fz>gk-s5D??HOOFP&CO2tx%PV;QhGiz~gr=a}X zlBO-#gm(-xOOrFa4nQInEV;-lnW#(nn*!O6e@;3bkM$lGF?@b61dc1yG(gaz@=AeP zEw|BD);F>YaKk56i(qdgQ7;~_57lZ@$*AyfXsA)1HFcs6U>K>CYL%^BVrg}9UUJkd z#wy-tTjRs!6Efu7#_?y~F4bT(EqT^~cUAX_;lXN0@l(BvbrV6y34y56)`U?ev_5Qu z>+wPWUSJ7#o!wH@e)Amjn>owhhuXqB-KvYk29Lxn~$+EopgPXMaOYoJ5c$Ip2;%aD3@ZD?@|W zJK-n9&!XS%*fZDz!lLUtjO*34)ZS=l4qO@E7m^5EZt6TvP7(EtOWW}A82Zy@309G% z2v@02>N#CYVC@woy&}4?U18Nlq^aI<;`cyijYgb{+-MvOIzPA+q3D5gl1Ja^BY%1W zea;FWbR6to=L@!3qvS130j$$5GP4!75&yvyuc6EO)VsdP{&vYOjMcR1cA)0H1w|-9 z=^E<&Oys*pZ*vCTc!*aV2MJ1%M{zb-A%|G9oZH5ehd0v7li6r178JI>G~1C%Q#-fc zC)`IJV@upjbm-?6xg&qosM8#_uO${Q8_lW%V$*v*|}xyt!DkD~k@Nsv4z`p4#V&D=tM z2Ns+KS~uSNvNeC{>&`a4W*?bp!cC*yHNk#EmNGf&oCk6u35hY9QgcBH!rAM+NzQnC zLkShA;HhP(s0)$33PaP&5xw>ViD@#Mk-6o~nD%Z(Yx;HOkzjuRYuu??a_~d7|1@r% z>YY5Dht#@PQ?p_DGNvK2jZXZ`ke1NLDkt?n{r-(>DvK@iB>WYpG+4RyJU?vtO$4hb zI64u8_WAL5GokH8g)}VM4;!ag&o|+jAdK}1+@6j7Inj{=KVchSjS3>YY=o>@4k+yK zxU%Od9*pk!m;3*Gf~Cbndn=5cYne~FRx5|?rUGaiGl z+Xjui*HOAO>VTjO7VY!<~fNv$x)j=pc%PD zmCBJTSF0`b>mo7(zi!4AW~f|?(ZZG|KRWC5ZXaSFsU3m=P?iH($hnB0EevmZ&9)X8 zMZSoOEsVw&{fkr-L3i9nMxz-GA6+5bxigsTdLHzFW32vn7c_uj?J2OJH4rD=nvbIp zQP2xMo#9gZrm0xPk%WphBEu2zX3EkzcU5#J?`yjr$E?-%4Y{xh9!rIrrZJSS=_LGb zk&nYn=%H{TbD8j<2N!OmSy1ywNz@d2i+A3Jmq2y(T-A~=BppN3GB8KtkIfDgrk3k? z6s?24V_5Z%y6`_Ksf+SonD(627woh+JYflC(fj2KoB?7GTR;a>)+F&kqiSPnhxDW; zY%RaPJ~J8ANt({Z?Xva;EcdoX3n{0Mq(R4t)Ms||%|Xrk^~gVOdd>R`#BB}QVe1mb zz7E?3_MLeCw@KXV{GC?Cd)_>m_k5G*40Wv!xwKU~jwQQE?-8Bz=G-XxOc)CS^L@=* zpNJ$Xi@%}YI5tyx=>}?K2Oj3MyQlvCi8kSkG2U}pJ10Cwgj!fd{-MgBV}dByDZRhT zMZ`odhFM#%u?kc8>Yu1*#7mxrndBAB3GNL`Snau`&c@Jj_I+WSaMO-;R_*aL^iz$$ zX1IRc;#&YPJusEu+rl8&jaqi(j{N+`I{pvQDTtX2RRCjk`RQnhg1I_9<_6=fS-DGz ztdoy{4TEQ)!4Cq`3ym0%mCDz9n)!*;6eNZj&|y%lJ%W>ASg+pFhw(MdT2^ZaC@v+E zIb{`r%1hAzjPO>AYZD`wYlor+mj~Up3Zb$PCsFiWFge2nt$h> znnl+phb5;?0(UsDFl&43oRM2jv6Z-3wE@#NCTUPlR9bUc#IE1iCS+2Ma|A&xc$`dHx zzwSbK^n;eTd0-H4VNCL*tfs+N|NDc_-}3x-++J}ZJ}(K%64hn`j=^}sSw0@w2I(3m zmTccIj+?q~YCj?rlXVs_OR;H|nvjqrYSX&WytB`zIYEgbIVxWneiL+G4U6?OsL+1< zUyzb?{!r~3s7>({Ip~_V_XDS6uq+xJ;C5e_1Peqv#5%yZMcCQaC3Y_@H#S{; zfc>8C?$r=3tnGkTgYl3h4Lf}w=`ZW;$2mbcA#8=e9SB0&c=Mwb=C98AyLN@v_>tP{ zUJaYk(7FxC^wU>8_Poi=XUj}Uu$Zi-wGox)*-Ik6x0>-zl|yAYGVe(T`>B6by@|lm zy2HUp4A;H;#OphLqWW*pnd*|`@iY3oO)_(Ht`9F)2pFNk>S5P$d&(@^G;O9r<87|; zFKYq4h`VsJ>j1!?6AVJ?xV2!aXEWNWClN1t@sN0LY)wqn($CGUrqq7q(YBd^Thu$$ zq-rIE(4+IYP%X4UE`?r-ZIh?%i&5JkkYNMBrCDfI`TbGL52XzewQ%NIW5}tIPz^zo z+iA-XMGmli`htD+hy_bAXWg4oaK?mw0-wpK_z?ck72EMB8gO{KBu5$q|MorTtWCS= zkJhyqY8-*=Bhw6V%OQ#+LckQQ$e8EKo~5Kj&9TZ}Hk|{g-cB}9#4XpL)?F}|l&>L+ zRde2|eCIOi0t^Tt0g5pt%JDpqHw;XuBrE0Tu4P+tmdi3NGoSZvDO3uVRq zpz^B{^+lRZI$q2FW@4w&!*9n7Ezc}nWF;B>>A$n@D7dA!l~J`ZZE#-6(sqNX{6^d5 zw~DoHkEj@PX2Sz{Op3Qke=KZ~vLv)em^~T;)R<~cb4&1A2bk5Kd!O|3 zVmgBw@~R_$37VtWArw7qCS4)nHy(}#`ToTV$pOPS`lFxU-Kv7CcU?sdpZ9zG&8{M+ za^iG*QT5mq&^BPShb#b)YNwQmN_XR@~PHEq=j z0uew%qK-*f)^&T=@~53pji+G;T`f3=?elq(l&Dwvkf@mvKs|IJ}TAO^644ZtdMwGrsR@tnpY7}CYXqrm(mWH4d+n;T ziq-dzgrt^DX>{ha`c*>atp%w&4K^9*a*buH)@1XpoSt=0GTmn|65P=KpOha@gnr3&GlaUNQpKg{t|K@YCwQ8VGa;_?I14&p`nfp}I@gBQoiH`dyFRli-0|VFh-snwov5lQThA5? z$wvl>nS{fq{kdBqan6fx+tNn{)Rbl+g^x88N*BHKsZS9`(8K5>y2c;1cUp_sLk zII+gD1FgV0_n@u&RWXgjAzz;B1n*oiS1~UZO-_kECyO;4E!MWxKr~N;2{sBP=w|Z; z{=8Zh%8Yx6pVQa!%6sLi+LRf|bSc_)<5DlQB$Q#Lbs0;3scmt-T~F3FhQ!bM#S}(5 zitwxgEKeIg7He1^2e3KLihEU^h{v?q`Xf6GItf_ytSiFCsO?M63=!(^ki%c4L;bKw zyATtU~6 z2Jg5PJtvdpZy%b!aJqdv@33h5gX3iqukF()?>fJ=*!$O%;fl^-T|m63wb(?YVcBw( zO>+cX8(}rcLp?Eu-S^@1fjIxV`%cGRt6ZfD5iJYiXiBSD?srBf%V@t^@E(Y>5Z_;( zDf^ded1*w&tMXx0+L$O!8Cb`->o%b29Ke+EqHs>WB?Ga%s z0?OZ%erW50T(We_-nbz1cYa;vgVKdEPj#;V$g4C&hrdgN@+0;xuZ7s_b)6d8uBmdX zmg&;Q&Rj27*z5{9-ZFuTZ=K~PsSGsvSkL&@_OZpP#@P?&b`5+hdV>F6gheA4TVMN}> zrM#V|rx~li9zoGQpO~ISUo446uPVNTWzNbZIrDI3ZV3d3vI^3A<7^%xQn=wm+G=H? z>&bi*-(o0-9M8NR(yq{8y9y6(BZ-k}kmU}nzBPh}B}R_{)sjg-Ji=q&&P1U44POnf z?$!y5)VZf8Paenv1?mQ4xc@rEYt~=d_Z!hIas_p78hv(olM8R7@Xp@5_9vmJ<&VsJ z*J0}7OKV1@cSx-B>1Lo9)b|*_D#mx%OQ#m2RIXLy?%LB`<1FmF)Gqu(`b*Co=PyI@ zgVxl+H2|^Wq+3&fZUTsxuTX|fYvO92(CAx=1bSA^tnMj2gj95r5$0urUq$tmL%_hi z26Vw!vqwvqipau=wQ-_po6fzDM3PnUf}8MX$7hFAybzpNmYq8&1Q6hj*l@5L+v`LI7&eL5BGh*JyUM$24sm(2+mLq2k>{NM71m7it76~F^8s`=P|#j~4h|}u(Pp!qzwJTc z#Jw+WO+Og$LcbQK+Rgm1kVhAJh)lyV zJku%R&kOk#ikE`31GW7$AG@^l--!@W`i1`s|EI=JY)-%9&UHE=*7Ule35xGa4;khF{`bzA_rHeG+yYl0G7Sz8emuOvnj z>P}%rng}>$=U8jM0_}4_TbZ|Jm2CHg8GS zgz=6;SXI7wJgwHF%<2`rZ$Io1vg8ph(~Yg2u2NjNp=oD@h}C#|^iNfRz8~h$RhWzR zQj&UcvJV(LJ=blZJ@twZN6QG0dChZxy9u1u62x|Ib61Npz6^PuOywv0a-{G6@TzwJ z-B=9XyO=TP0<=BeiBN!MgyOW&*WyMRG3Y#+bgnQCbhEsWRdk`+O4GQWQ13{v08N6d ze$~Rr1fSPj{k&&T9bLz=@R!I!`QTi_G^1AN$C@ou+~t7#LahU%uM5oIoJP$Kn>jN$ zGND8cjyde{+}$P?7{u(;!EyEa#8$vf>4$KDC0-3Q7vPO!a`J}CJ1yBsw+ z;{S!+Hy7dI=MJtmJ?p3YfIKvyjYIYD=V^sV?iKf@lvrJb@s!hZ(7C;Fl~9K)SovwPO6wjr#p`5A zh}V>>c=UB(`_RV{1Z2ggP4<1L!Ml-?x5F&+@kNot)^y5e7vY!M{BV~4y{vweX}IMmjYp#=`V`51>Jpm= z3EFhxL>SCs^cz)Ds*e!yXr75upKf)hJ3)?HyABL9-l=iez@w|#@>;ofrk^ce?Fql$ zo`lI)fLi}%KGrc4dFsC3#Azi&RD-m--Wr`GZ4t7ubNv}?&rUk10G z#>>Z{;?1I*g@iL`&V=>lx+7M+6)9VlSsIp(W4>)$_1M74uU#bfuSqpql1K1&eMc7{ ziujEJ=+BOp^C`UZ8z!jCGlgUv-kM^)%vEE8ZXD3+-*lx5Yh zTyex)%i$7VbwGT6Ur~Bw@ zS$Ojw!q+OR)u(l@o;%BqkMi+B_qdSB9~m@S-VSu3e?yMFhvZkue7|&SU414LVM3~i z_#(TCt;t0~y=nEiX~Q`W9L_f-(@5w5!pN*qM}ZNL%C54V_vzJGf9wTD_h#&Sd-l8l zJHX#ryt`i@k7+!9Kn9?>@6i@-j#YFQ#~~a0@(aV+hYm4{^l{7oT+?pL-80 zn*X_OHRo6(Z;GPixdk83DA8i!*`RsLG7i}Ebhdo>yk^6bB=3HZ8*5yJ_E@|kBh4br zsGlQy(3%TM2p~LCEXD5LH2<3Ih&Mj=VYRfmT067;ww3zWyaYBSVLf?Fwc^BuWwNj# z*Q#qdXCsIc)WJ!{s~s-l6aMv;Y{x=7BmUu%AMLFytK&1)J!iF=`IrO7N8Ep|_I4Vb zs>R8P2!_2Qtm$Y_oS0FX&ErRI0?C|kk2E>WQg8g!=qi3*0;#Iqdr6;^Jz@8S!r9W@yJAa{$-=X9~E{EgbTCr zo`#wFtI~LVb=*o6Z!HA%XNd>3ts*)gIp;80)YqKZ7X$-Lr}e7L$5&6pqN=nZhY#Lc&7Q4PhwP!Uwua(m?4TomurK-^*JA5 z6pk!JX{L-8L##~A+-xwWF?Jh@SoA!7v+8#P+k5SL$Q+@{@P|qOjeV(4g#Qe>YR@4* zVy4Kq2VEVbj^oTh9lz+ruCDK7_VI!z$K`e_4H-3WRgo0)h~qK8i#z|+v{L?t?*(*R z%#ocLRSCf^*cOxS0(oLM*$#d-$|fl^GSrz1W^R-1VkPSiu0cOH00`1lh!aiTS>&sF z{{-@j5_S7b6>FsDw0^RM;c~q1=yrLxA^>zbLKjES=-s7qCnJhJ&5LUIG4ECSLA(G$ zec74d#=Nfmux)}BbZNU1$Ev61@oz=fDT{MCoWIoVLAHysg1gv4qJqOpg&&Aq=IoaL z6aNnGtb8MIjV*lfkR=0R%k`&}(v+kkwnK0KStDEN%#!T~BlJlfj@d~Xt&HPmH_ z0Vspis~fmjMG%Ko2J;Az2zDyJG=M{lmI>>l#_bLHn+6E}6z_4h@!Rm8xXZcpXZs*#{IK zyEu@{2DRg62%OrAPVs!nbVk)~Ur`2IepvOPS_bCqEhe2`8BC_Kw{1{J+42LGsZ*KDkW&ecU zvEh5}n_KE+pP-vn4&zKObx}cQFk(XU2CeQiWjSG*@}h(-;6H>6zY6#R3$*(Vl5r8B z6Ag!F8?tr(@b;Zk7<EcPO=r zARj0neI%B(Pr9`3oP)lppU;w@ZtPKTn;b{ZFl)%BW4wG!)p=%~>-5UqY7L;^pg4J} zuE;KxFIexuC?8M?6_}!#xtzWth!_*isJM2?O@`DgSaR^}U66!J>Zzj3wk9=T+gDl( zZ!kukjYU9&g0+rn#S$7#D7y`|Y9Z}H4@sM~*_C_U{DBHpi5WI4w}4xPvafAPx2?r2 z0+@daCo>#6({|n4m8r1VG=s?>9HDMo;!n3gps~Wc+L)c;Po^GJGr6zb^1d>D&d>>N zh7~O7Vq3`s{erjTN88#%4H0$C=FMXN!_-;+HNi(woKR3&kQNXSkZzEc4(aY@boYQE zA|DV6)BE(*ub#zrt6a zyREvrb>Q`g%)8IW7mig+H?IHL4X6gZsp`<0E1j1X5#j_?lf8~jhy<2r;!X>i;LEZU zI^#+scUotE(*5m67<8|)pLvTIyFm-F_w^?nVO~=XtHPYD<2cyaGt2u-uF?21 zv5++bs#FqHxK<_QEW`Br2XW?nZ29;|@Y&DrbKKk=E;9u7w1ERwd%)Ev%gh}Qj#Zp% zn079-Z(o!H?Ja{cn~KkMVInn_fc~gOQx!?)A=wyO2%zIrX$(rjt*PAD$#om!yh{zs zTRfQ>n%$$s;#Y40^7X4DbAoKIx<|}^iyvt&>jI4%7L{vpa`bV@;0|{nm*HNSS{Zi2 zv~=QZ@yDod!&s|6@!y7bRK7e*N$SrQWH!Kvd_C9X9B)6l@G(nm*bb+T#c8#8bD^k4 z=}xEy71IZG=X#!@coW#ltE^rXl_F$V=lD+z81vG7!6rJ4X`ni=s{Vb+jTlsj)oB%v z967NczK&j;IK4YOcyl}H?3U4zZsX7-ZdQf0X;QK(G%JvO8@m%FF+MVZZLZDW@5`O} z2jTLEPdvdl%4Fr@w#Xl9jEzV`DEKxVH+AME#M@|pBFKwq-(xF-c2xd-zHO8kv5WE) zxz_Qqc{-~GAAGYn>luu63NaC`$ZE!!bmC?Ckt!6cQ|AQa{PvuOGOOtak5rU$TzOQ= z0#7k#s?Fbq&iahSYc$_HCoFc&8vjg-Y@`GjmdY)D`=c~?u6kbBv2DfmlS=U)1F+ZK zQp8qgA>5*LZ6s=E9p?snSg)#MTH*Xnz}s(=LL|Py{Os*_?$dswRWHz~HALo><>(~0 zgKHnL&=NArjT!Zw!)}GI`G2zs$NxAXtFeT;WuVBoXOX95En^P)o4Qm3Q6Jebnh3w^ zS(0#*FB3Az{-BHjPh6=ReD$bxyT&Z`u%9tf%ntg~WR8B9jd_Dp;v;{JimTssQMn zvgF`s`)3%;_2Fau$UUvpGU*qu>ghhSF8+qgm|G12&dT&{UhJTYwZTE|#GLuob9;nT zO2xbV?U$q0uMtjP>``#*e}}%5jj2`^75LD(>F^+nYAzDfM3%{rq1*O-#@At9yr1Y# z6^}g23@)JQ6odwEf3qgKVUyTTt|~=Yt%LEas2@yJ`39EdB;-2zb?EaI3a$|b@(1P# ztDlx6UN%klh)VHz9PVtEwM!Hh7_0x@l~SD%EHf(ONB0`e>M44krx4#=_M<$lv4FTi2Us z^@}5PTEMu5TN^4_=8Xr}M1o#v1m5jNIpj*MZSuqNK)R*&EB0LqQ1m=sqU0W3FKC9L~Bb0@rtED+QA@@`cLT|(Hhhs}=S-H$|1 zE?8)rGOkV`MwlHNS=B%!OoX~~Z4#Na>$6W={>X6UEh+ieT+N3Uy!m$L$g83;plCw1 z`g4v?t-=1Ay-XI7YGb0x1)e`@aWrERm7DB2zmrCr@JLkywHwgpD!(0XicHVs4Q&t62H)k*c-e55m&e7$Y;7KemFab?xLHb*`MrkYZCNo+D(3b zv;4l%?T`tBfFrg~T&aU@46^shT>VvdzZ>1M)}1LCc1PB^i$?nH;$RI4)I6HGr}?U(d7@hiaCtuNN8;9z{`+0vB2~K|8!n)ltFvRg>I}O*?Yoa9H0MgXzFf*-L~oh5DC5jlpM9zEm!*H6eW^v`@NPnY&8Thk zD2MDDwVxPGRC5udO+PC?w=T2iePB64DftpJVRjeti4#7@`m<46`ZOv-lwk!pX7L8j zbat`Ty}J~jWo5rF3cUqGkY}Hv zjV%i(9iFEH26+vI1$q-g9>qNB5=ZNJ@9FYR^{8C8JsNh~4EiqO7~0zI7FrTJ!;EGH zUo)SDU?-_8hftC*4F4K$*(0ww{zj_vVGQ!_wB^N5oUaYs(E2qF-5QCF?MoU{s2fC9 zMnrk^kn9-r2o2ybeJS&5#QIq8(89Hy>EIU>*n=Y<`B?6tQ?9F$6J5s!FjFKZrmUE+ zv8#3K-d@_g>G-Wn^DII3>%2Rex-87bfvT!x0RwClIITCGsCgOzkqvE+I`IW-1WCc++QFdCS{+ z!!@(&M3XvZMjimxX5!Q6=&|ZjGke9xos-_Kdfp|hwPZNXT3;hN7!Siq{WJAB$SpQi z$ot!Pjqcv%DdTPO4%}w7F^cT?Xe?Llc73}u7ZC2<)uvtb@Rj7aHM)BqX@1eT1j$XQ^vc;dI^-S2SKn zSIwTK-oXZ8bAyY#7ZI!9Y<-}EntG!UqU)4u;HP3nFgR`X%Fx^k8I6+oXMhwC3QPmc zO1-j-R9Bq)9+QU7>is=6+QdY?fHGYam_pU5^*^-mhki!6WN=sG-KXd0G(l6jJ1x66 zM;&bkr^4}0a1CS&nEoh;*I13UaPVmmXycnb|3g;3J!}N+5EMWC-ca33L%D^trais}0V!YSorK5UH%Q(}Xh=Hkt(@NDs`^zrMkj(njc?_8qRUyIY`0~e$ zbFcSGYOeV@OdTuZ;4#ikEMD`SKKm9~mi2e(VMPf5j4SmJy3iEz7z)cY7redQ;s_pF zpo{-&yb=8f^*^la3%rTz`**+hNtK2_nht02^E}7*O`|O8@vmo3kl9#8isBZ#Mi~ed z756&0ac!mAu9uDSb}X6JnYwy^E-u@*{W7E#sW92+B_vYb7`z^9bMHp8z$Z0Fw< zq_l86iMA+lyl2|bxAt;S5efDBHrT(%IH#EwZ$2#k_GbM}B6>KBf-bvkR;q#^SNbtz z(@sDIg|#N*{rPP<)G+Z)Q`!C8QKNZbmjz_e)pyUQJ*at%-503&2{2tt37L^k{=ui7 zn2$4h4&m-g@R|E^o({1`uQG<^wTy-c6*J1VCFbj`v^&DR9KTzcwyZm6m>YS|u%@Wj z01kQ!d!Xi<0rW99h}Uh7w)sGkHLB38P7IytERf#qv0~HHXCSC$7s1(V9F-nCiJa;V z=gyhq1V)tEsq*u%&53Ttv;Bu=-1mOTzxWb`qBUqTllYjDRD_TC=-ye0fR;}E?mvCQOJnz^jWjYQ^5nd2a>Q$*E|PT=5azgnQvA?N+Dunh5EKJx&xL?Mdff>8j|w`Ht!wxC}@Tm;-q zOWUQ$$}p!iOEed6k2?*2vf1(?>clm64YSzwTJ7?8`|g#<;;L~XA}1}VU_Ew zhm4)^pU36j1n_M@b=oqEF5%_jE(VVbhyhJ$gEA2hn?ajqV^Z28$?XdB@h{`vO7JmD zpjyaGHQqOs^IQ{A_AOXBK(Jq;GDD%(r+1c)r759|& z54RdrixS?ITNdE9R*0({>3?WOt%sn_i&etWZsV>XkN?oXJxqUbYYyC7M-Z(|g1rGJ zT>SdW39~XLr&S2bXnw_TyT#vTgib9mWbIYO+c2`#Z>Ms<_zV5--}R*u^IEIdw&@ke z(%VVA4(ai`kU;Pvg|OvmP&D%|4!Z25?KC*$``}q_L)2MOC}dtNN&hNQ-8c3YOk9B< zxhbnJogmbkKzG;%NKi>6`7`4BtZc^F%~+s5T%>7X0m;n8IBVYDKI@EC5GgiM;W48>;SFZ1A-%xldS*OU`b=4@i)r%^j225D4!V z`&Pcl*+k^Iy2SwZch-MijV73w-NUx1X^)k=fs)knuQKQhT{0G9J>ZP%%B}$b za!ni4;Ntk|doH{$@ISP7^#?-00gjSLIYq^y2oh0PNY4_3R>jQ5?#~W|3^B1H6L$>n zyYen_x%Q@P01vl*CNpWSQR5*aLy>u7^2JfDc}9iYSVig&k%<5U)w<8Lz+Nf7(J-oM z!EljWfoBhYxlcfmwXu|Hjqnk2+x`UW*ClRtZ{20?^LT84H`Z}-xKZ|zkyWIcE2Sd%L)2ay+QF) zjm5CB0Si-S% zIp!(;Ex9KMg+|ajH^}wwWxy8Z9Avz_kT4}ztSnU{jaMsr3AW^j{7T9G5zaL46l?;p zGY`b?2995mAj-u~i!Zm{5vY;sO*XW&Vcr-*K7}tg^&zH9jgx!A)0y=1Rn0yuk;7fY!=DPaenz)Ct?h$s(LqPfx;as zcYO9|KhETNy(b$xxb0SaI4uaGyU;$}HFaA)3}H(~bn1HI#B0+eXwo;w9_`V*5mMUc zVrV>-k&PB1w9uUgW6cyhkhx(kNP`A!9p0lW<@(~u^hx$l zJ1Q2>t|_*S*6n_9z#+$4jH-=Vm;V_c=3re#?z~ub;R&9xK{#9~6*^bZ?KN?vU3Y}j zV%g;sWcDLwtJ3`Rz?C*CN)hJ2Z!5ohtLEJO78j2=C0Uy@h%Ef74F_7}C``-0(ukM7 zW!_?}V2iq9m`I1cr97Pe_;>fUb(&u70o*es2ENrcp@6a)Jd$xkZyv!Gjd*TTD#ga# z?n2on(3DWEdz;WuDx|)Gl*Og%G|C7Zs3YK3|GYzOFTyas z2f59=-q@p)hts`cZ7t&pO6t)$ry7V`b~ENkswfsxTb6@pK5xerA7=+sV=7NV_!{x? ze6dgS{UB-CmljKed)w<4xpdH$ZC|lDf}4J%$#}|b7$taNVYeg!Z-h1GpZ;NXK$8$J zLFh95<<-Cgn`EWYw0mJHJql>mf^dc|9g-d@nbED&6{bBT>OK-(;#>TFQXaKiE}ms$ zLESx7pzh(gJf|5f4I0AEKU8B~5Eg0#O7(6?jGWxll7bKX8?+pZO6+p9D$u8KnUM1J zFDr()oPODh;6y0d+qsfq%XV?I~- z9h2tn*wABxmQFo=<43I1?*N%^^Wsaf8C+uSo3fd?!{-Iml;$KgR0{0nTOJ3Q)ma=a zC|!cc&_!U&;!gKXm>zsc7Qze)#d)8Q_OTRKHLX5%zIO_tIf?Hu=?C~e zXPaF-`pc$cl@m+?4k+2P@5lmRWdoo%fyc)5&BqaX<`?-cYEF$55oN<{mCLa|*{oJA zG#Pb^;L+>H(t9w=bG$PXh;HwyP#602L%V3V31HR%1S~LgbJ5;>O+kCQ7ox~?&Yc_8 zOyyqKC28HpwMfE)uwJUf;%fOI88U&pr=L&x=w+mn3T2!j2cGDCV(f5e6#p?&pw=%Q zhph>dwL9~7Zu&^-zR?;bXGa?_QQf|iZo|C!CqUijSHJh@2<=WbG>HE9z7UOxJnOmK zTE2mEgzxIlW(`E}F09hT*(irkZSBBgI(467*9>hZvsbrab91eQ6DQ?c^h$_C&?N6t zEHB2TU%Qh1j3oR5>fg7XV(z;Xs`?0)8U^Rx@GoUun4WOX{FS4Tta}lWIcH94UN5Qj zrGZ(TFJJH8xxT+dzvN9?|5t<{28k&$Xz7R(KuY~Q+In81{P3z%@pd5A-0!L$5*e`< zf-q?h&fhjP$nHG;DO~K#iPizMnWhiU-*GC*vPND9UkGPJt2#LY4y~G8uUSKobfyPPo^{wO0?ABoO z7;y8nZOw>z)7A~IFT~>lQsT^vEYLW(#hf%(d3C_;fA_W+6pMIhhOqVM71}lOn@lvh z#o;hU9`pCd2nT(5PdJ&!_9bS?MTvuJ5cbi-vS#QG9cR1DnDy2U6!7pDE3y5cMz_4_ zl|3gB#BG(k8EwwkOtd>xuDSd7GAq@N-!E4>@bnj%O0Bzw@q>_2xZ=biO!%Tk%bn`ZGVZn55?vao)`&E3V5s~Lm!3|dmhN47_s*`uHxZe=7=$K^_+%JdvN zf%jgxpwdt{z5cwU_~K(j5|x;@s8AEph~M)N0bN(FbRkEhQz3Dt;J1VC(mr_ne%gv5 z84;7{^BI*VCFNR`DId|u!&I*gCQ4lSWuM0>8ZxpaNyIq^)V(E5p)!u$zJJ}b+^DHR?&kmz;ts4|zz#E) zBl`?aQAbEiZt${J`yLseoNY|W)E?|D9rxW+I1dE{zFNCe%W%f7VAco6bfKymfH&n} zdpm09yHrytlzloX8Bp_+-fC9x@Uv5?KBb`XheOid&u6O1^N-wzYLMg|iw`<4%=jO4 zsP3)#@vzBAw1%J!8J}M+n}CHT?{g?60k3O{39d;V{V%(P0-yD;+braA#E4Geh&caT!7h|wwC|33{+alHXxo)v zcJ`%g4w)Qb4qAC=8 z)EU*f*Ngb8w-(c)JIUH7qs!oUpPDh~YuI20(&lgXpTcp#aO&9}?tlj00Pley zao(Gf-2=tAvhnbZe(qz@*hdkKC=TDE^~J{-mw_}5i(M2z6;f^3N)DnG*i!{ z0NZ}Ln5lG6-~ES{`Y@25Jm<*COzUGDTMcXum zFtAl6-F05KdVf(p$e?1*6n2#*pXU zuD&nID%|zzuQKUf=n!TP8d6gB!E+T`Sx9)qUkxwZYAHN4zYkQ;E1 zI-JOdArO+<(8}($x%!m}{-3IVOt~TS(mN>_va@(+36`ic^<>cSrj&AwpDjiLbBaoC zqqgW{nI>!bLq9YsB`&^K!&b%X&h-7pPr)F7s#RBZt00VOFN_Z z!B>w=5+(JF;m?}P z6u_pRdL|u)tpMGpn{4-EcdjZG`uA7)o%>LJE$m^#hRxV%utEUJM*3zgmx zXAPI}TiM?q9>+8qF)R86A%`rR{+_cg0xqrZwucBw3T;UH21^XN0SAGF#wD3BF8rTU zko9Lql{2iQfND{}NECk1>B^W^mHE)Eay#&`(7dZo4Wc&ZS5a*9f!H(}=RH?mSXN+T zFH1`h`K&pAKP4hAO#-^<^H+5u zEI%JQ)aFA>I^dm`@kk#o&I-=rX@|D{qS5p)nZg)bO_9`;96<7Q&XXTY7~JK@-fR74 z*GPFlKG#{GFjg1(B0ciP-XHoQKF#|QUM@%tE8wErN}LFNXXA;x>RMlcI#XEI8k0ZA zXXGy%uYJpN1ixqDS$1%!j{h01TV|jrs$jic;3tOny*Eg|VXoOBbNeyR9$^FaCJ z)q`-nDR<+{?XBy0x%k5cD40zX@ck?Wi-Rl}Nr4}_cto`MvSS2ydim{9J6S^u&N(5% z0z7`y{??e&v%;;Rc$qMZ@tJu2bR=rpneZOc)=*FbR!IB3g=SLekC2vXY3Hl3EKTwnP)Dc6^wU+RkYcgh^^9ya}LC5Q?s0J6F=)wp10Bshn!0d-dk(4mdXDI(xRvL`S9jhtS7oD)I3_M~FKFn#4QSJL?7JpI zQtj39>|rxP85@ve!xQ~NZJTJq5pvl%NVs_h)8~GGv74V{KRkRuz3p58L?2B)LX0HA z_daXR+#E?jAMYjZF=kP#C9axjg$ZvjVBxE=V?t>^4HSH*V9-3{t0Z2Cd1f2<@}G(j zF8UIX+@x%Kl!Nj0g3`iTp79;OTuHK}Zq>7it0+U_t##A;ecqz-1M6(QNd>A6Z2gzQ2|Jv9~ULvGqa5|DkC>jXKWXCcs^6 zppufk`G!054O8@OQ@+ltNna9V9t%{kFFKvno{1xtCjPIIpd%_sDCqi#ijP&9BE4!pW#)he%H|W5xLuK|GD}^VU zR^ba-@jA$%vB{J+^GnU{kWqnSQFCX#_I>UB%W}U8R2;SAh65++&ud0;KY%W)vm%0^ z=KzdlFj^-yEmdYwBowy}y}>nw{msTDo>=YF@2uMaNkr|h=dzq}g%+IhJEjzTt)M)1 zJXh1-Yr3C5ZCqwIG7n~hR<1!PB7FfXJ~)2Lnl2g6WNAh5Lk&?!vh^z$@N)kQ286MS zT?W}3K4{_UpskTDG|Qu7_j0To?h`6~E!8L}uJgNF;Fs4?6t$avr+K+7V`C8av;qy27u3k&z-0MaXB^x2XW4ZRt0BZ#v}f4tWGU&<1l;7!S?VGv3It6gR); zCuWv9tEmTE;EI#UZNtFrWLYdiRi@2im;B6;ih}1XKN_@W%bF}|!<6box%lpxe*WWh zA)YECjHmq+;kxcrXdg>vpMHE{Euaj*8jJwc)pK@ZW$|nC-=*E%at}(O5-Ha$E|GuS zw+?S+|C*ni<{U16${xGC$vCBJA3#30jZD^?5Tvu%Ys?Ipe{_Cso_t}L z_}!V5ihw3gJI_=g+>>dEKt9oRN?Fi)+ST`=LK27KH8K3K5|V18qHjWn_BFL5y=2$2 zD$~l7p8b0QDHyI$%KvUoHJR>Ich1F3*ka-^llIgT>X|M|P~lLgr7+k9M8P-uMm-_9 z4M&6;H2vaI+tT$_R6CHwm>Ctbs`*c9wWIN*G1sfs2eVn^1(!yzU8qOb-XjA!`E?sC zBt-Vg*WAk7E%JbpI=k6Pu2L_D_$nu84&lp^cAIfF4wrAi6Ydkmb$2*J`sKYe76iBI z^1+-!o-!p=rL)p}8!jh>ZtKlAYoW-SE=CpMkx#;}ohV{*;+R^1)^~0^?IGl1#o^IA zKc-3E_xCzw?N&L6R2Oo}gKj-6(y7eH1t6=e}=!eLBywC87IVA}S{tJ7oBQ7{ZT2do( zn=|r)ujA5|8|%{mFQAdn8bd{FWmU}Gtp|eRf8UK>N$6&-Q6Hpe99I@jwHNH z9m@CdI%xdO?ziKwCeXH2d;AKk^>XCU=ZvP z$78I#+o8c+`*DGu`Tx*-^g>00-`Gse6TSrnf1c}lRl710F^-hJ;zFtdS{zzwHmvyj zA@sX6!Kx++{hrXy$!MY#!2-12UkM_q&-FJAui~kUs9)v(bV_!Afy;9rcx8dD06X4s z6KhU=vdfx2PW$qpk!MLkt2vm~>J+(5@6nUuFN&NOz~9GUZBjy1`7vs5>9B@4WO@7G z0ds*zN+0V}>je)it@UN46nmp^UVo?@;Zwl(aTF5?2*WDZXdxgmy+);2PKX^w#{6Kh zpRS3fVUTVQO?^;Cv|o5?uT|kN(!(YvvxEN`8^7E9h*u5ZRG1buLa$YYpFUzRfpa*I{lEx(trZ!dUFmDxNOW zP%X6)*_1ttL@gZRXnBZJUzSTG60gi)y%?-X6a%1QD9(pIjpeNzpJTxfK3mk%0z+o@ zIXJYzY(5@Z=5Q&~Q0*@Kh@08Ts}|me5U7~!PsVVjfNIV6RjXXKSePUlBlRkA4N_E% z&K=cNb`uqYzMRNuYO$Z86O)rmYZYDVRpyabg!x6*i?C$l7C18QsaWy+6hWTI*1hpq zx9asD+F&UDVu)JJT(B&Ha=wb&X?EK#qcMl1lLdN-yIbQ(@pk%e5saGs{WB z++lr!a>BAlTZ6+^=k$(Mni=FjH0;=%LC%i?Z5SA(XgW4~9e~Iqc6gyX=Kkf` zy>zr*J(gx73LZ8HG+oP!#wRm+`C~_NxNb!`W$E_W^FWo8*OdOaW|1h!u0;hpxj7P* zE-QX2O+$;Pj~Mr}*9-(v%>B~_$h$(act>w!9@`i*6tMb!tf&(b$5Rm@a$|g7nPl0< zVJp1QSO-_IJcPPDa;`m?{E^A@yrIZ;<3WnE-G{?V+e&_O_2NaB-XtVU^Y zhszrH^5k9?i9ih6@4G9m_rWEwPsCdBD$Ua>yc0G9BmA-d!joKkAfTIyr;sPWtbdK= z{$jTlf?Iehe9>PGPZ0lDeHSa5qmJz<(5!YHNALYqg72q%Y^I9!Bf5`M{J)yLlSHNj z4>iD@Hu9_f%bL7@%u1%76K8*T$9w7NPtymn?N0-fS^7`RP zp3tYLC*GT`|9Jk>VrEj^ zT9RS%&)mNM7?z#PTF7(7;lOT3j(yXdHqaLD|bIhP}*;m zs;5HfD26KD;nb1&R_~f}zJD{rQ?SV0Y-e6LgW67az{EHRHa1H*Yx$Q>QDNTdzWax0UAX?Tt8r+YS5Q&w~MNHXmqfu6FX@pl5DoWVrfkHFjFxmZ?C1 zxF86k(L^ChJw~zZUT4nB^A5f0{iSv^NoUju#VZZ1)DdwFC5fZs4$+Cjd7%Ffp6T4! z%cg$J!2zQx?KVFqT$(Ywy)=uaIHXijZ`&dH?JEFflw7{2W0r1>X_r*RPviuMzJ5^s z6^UF?^cDr$qzL9t!4sg(yy@(r@t06+AFkr$VsyTpg z(|Sh$zl%a!NOwa2-{}tfLJeEcYor#p642c@xVWWKjHNq>5YE(a)ZKJZJZXE`4JBuS zylRl-CCvy6=w}2h@(6``%&Kdh9muDdHzFuh36<`g2EGMKak_MF`!il?X_(e^GS^UyK*WqI%%5+}Jm zwQ|=g`*+}#l@D;<_1EUWHw+x!PrPdp(NULA%Lzl;c1kIts+xVRp-0l6`)l_ZAlzfA zUp&O|aV^}T-RNiPy1)^`;Vd!!W~{muKjMF;fq2ra-#chwZgPIQ9=GF3b+ylt7H|29 z9m_T}UZIKFisi;;pq#iBYu9OM2j&^%JK|UCvd94iC_%o|R4N5wM!3#5kPk5^enD|3 z9%!@B!So#^GwiN>sZg6NF-0AiWtLW7_BK8~douVb9hMN-&rl`zjI>|Kg!evvDmt^t z2d!R6`%y$>p)SripiHKIBHs?*`3@}bSNVFyy5?hzVPi$3ilH@DV2xD8A+e+22bqJs zk`yY2%g(*=L=niLWZ4DmdSp#|c#NuSr^)L&hg-S+dA@!wP3oVcz3XrG@#3}Q)1WGN zA&hyyWjdp>0C0F~rha&!q4_-@a2az)&{X9pB)q%ggW;=UL53~pgfi=YAsv$OBw*79DPNy_M zqQD{Pd{k#?{>;gNj6P2KK-Y3Be4h35Cr2uQrB)2M^RuO&kH$#N-rCldE}|Ucxc60G zYdjYKcrQjKo;=?;SXGVue3+55<&tb|wG2?=h4a$;fr8!ej4P+dEnHxeA8vF;GHkKs zv~9jKTobi{sI_PQDFEwpqY-o&q8~TqXZ=Y(-&@_kRxgewb@Xcy*xRnseDZ)MoM|)# zWnGeZRvm)CiQ9=%OH~0+RyOpxvh!DAzsLnfg_m6m{94=#u)zDL{&xiDPRy>6+X0B& zhfVFK^ymruHmUcpfn>nTShX6 zg!SwFzm~?0lmd7q2|PJ#3l)NGX;7-QM_`uu$y^Y)K1cSz$La8EyM7MXI5ziN^JOrU^wd)e|P_-Jcf=R`oo#4{D#@Uk=?*JGO^(w%vr@x_&#{ zZ3sps6}1pyh>zU<7+>WU#qYkaaNKpiB&*aB??(wZf6|MqscZJgyJ|cjj7~16|E%OnR_49@ z^k>%VR1AT9c3Uwtr{h<5n+np*^SA*n_)rmWKn=}D2f@VdoQ z^Ieuy!@YsrS!o1^m^7ili~8Y;@#zHkAg@{R*ql4B&t0V^<1~%Y+yuEst~Smg23vU}x=Xur@{)l?>8cdGtNVxV;9Svu%objAFT$ z-+l6<-u(}a%NDJTDR>qa2GMtSKfyzMK%0oz=(ei)E1IK1YSU$`(rF;KaB@W)p=ci{ z@nJsM13mr^Bgbw=i5j=uUP{>0QH>&O$e+@afClHu*zS-krkqHlD>)yPa|5V|^&U zScO6hNwJRasr3@8Kz!kH_slG7%FKW_nCyn1oVz?L+nm{6difFFt$7B_PH&?jU~-tC3R$&^w<%o;OeQP4z&2R2&DeqGwHt_FRWS%Xj^pVq{AxQ zOMSo{@vlKS2&DrEkU;XkPY3Xnl#DOn<7avP#IS!o)mBahZE}9yl z^Q&Hq_gu9h%P6xXkm?#plQDyPU@SKGjq`M|yPEOi8B3D)y|mEwWG&h4-|`k21MA5o zg6}#hc@8^HjYK3GuhdGcyktC#)%0}{c{nV9!z@6tAE{QgsZV=adZ$sCPNeREXF$x~ zuQ9*va3THwR7*<1+4B~hOZ4c+OjFq?`XPGg{j8_i_gT$8wVtf%;X2K=ZbT;ek?@|p zEaR2p-lHNCdx9FBn<#MG?sAG_hH2^7--s`zS?b`w%%ulV{X~_yF7ROoQ{ef`d&$uA zRAo))WI#5y@vFl9mQNHe6)fZBf=^pkv_bcIKq<8{fVV%sq@b$l!t3_0d|c8|l0%lP zQ-7y4_FF_joQh&zE_j7V#kjkVX`!NttL=9RRSHCZfJkGZ9%1@X0=M=~W1iS!_$;`3 zz1^a^?>{sWl!IY{hGiBGd@ms;JNl55y2^O7Jwk2)ho+tB4EMmmcjKXcv_wys|Dh$h zYlSLO*>6Q{HZLA=bBBKDiOcU|Z@-p?jCJl)J%=k_=zsl-?IRY?LJz#vmH=AmAUtYvif^-IGr8dZT7i*$C$A0soFmx0{yU1DO+}UZa&S< zB(Z+6VZME!9^KBpQN!%{x7Ezc{pE7*#-$x$a-=U!n`VWcRSD;kWPGr=>2dp-9F~91 z=foEuCnmCZQ*R-~*R$OdvrfLsl5vY~EpJjxxp)yO`yF^r#eUM){WzTY`zRRPgq`Q* zWF;X0#EmQlEx%Lh28^ZZuH>iOJp0sQjt+~SW3%IWS%_Ts9innGy}5+^CSP(%Xc@(kmkfPJQE^I+wfZq$@^lEL z4UFL8N53(}L;w1xTImM?)uu)4X()VBVYj)*YC*hoC(98mar zVr(7ReGo!&LEaqyKY)B{dI%lJzU@k+ z^$9(CwYpo(bic@OoATx4Jqmh(e&_wj02&>806#o?c&s>lZ#LxDu?=#pTrSTQM1sOj z#Swokc%E8%<{0ndAEKV#Kh!WGrOw06szD!Rc>~v z?gL8q*v@8e_|xARXG+=-<8con;ZW%lgzfF&uu+w4Pl2@|x12-3C11a{QQGR{%-wU` zu{Gtf6O!KDwo`*HvQ-UV zf7{90C?B2HdiwZ?`Y4@lN6-IMomD`aUDLIxL0hba;?^R?-Q9{?i@UqKB|w4VR@@10 z!GpVd2o_vg+$j*C1bO~^M{oc09OPi%vuDq&b**{%g_>eP%_>!Ty1yF5Y51BTTD>9! zl<2w$5ssT>gVfCv)|?Id?X@)<>f=m9zR<^p?s;emm)9Y=5&ssLelI7L$#a4gfj=Mu z-dmgfB--mR!XX`_zV4pNwO3d_+kn$MbE}G`z~C$$f_5WP5^ZAXca3h<&SIt z%*!bi@KefDEAlUYc4yFbkkEebX;$!fE-(jI)K4t=@Z8!DbRmrWnDPjBzgrL4SKckY;Xg{y?Y$D^ z*J;q{Y}->lYB44_Fqxsqs}7#$!R}sFgi4BI2tuL$O0zduYS7HS>?onU0OcK(W0|e? z_2?1fOYvClBBXbOH6yP0=mDfwor|4ejS-IsMRw@w4fI?A=nf*a+F{ggbKfcct?35BLnw^Hb(>#UPqDOF~gs+ zn_xb^b&={sgH^T!7hR66*lC$pTE>4n?3~>jFtB8 zC`-$I5pM@{EG)o_9EjS*vpUmvmAfHoBxEkx+253S6`^cmONc>3Ou9IOG2opZKfCA@ z+Xf8rD^^;RA9xm;tFuRv%K(pdQV-=fpJ)1O_15!OF!mwQ=iikmww?};iR78~ax>r> z8oS9?sd;(gTxPN4RYdb-d>e2px7Yar$MUwQM=4;jG5E490az5K6Sd;pP8a(5Vm~YP zK7F=WBz4ybf41Gr{l`sT*ZV8A2u>Hnr|ZDj>pRxJj9bjc`2dJ^Pm!WO{VL_;>}d$c zIs0#@GxCv=931C@IbdlUBvZV;0K%@3l%bDnHokJ|q1+ zP%Ic_(WDUm$*kLRLhI+b`4JD(80+(U!#?1ZEWoAi_l8}OgIH;1j_KXwxuGC=Y2N_~ z3On_LjWu6SLP(%oziQ@Z9EAZyu+*=>8bwQhC9^f8iG~j2-GB+MwUF@nwBcw%-Y9P+ zGdFmBZUbv|?J8vm!A=kUo)BL;Q=HUyZ4cW-@#?fz5N7V|9Xk}L$4o+8GB1ZLY^(xu_D ztv<@6S|gx+Y@bYtVo&0JHDO0m9F(7|VvaLpQl&w*^GX|cKj=zwI|sO(ET>ed7h_C4 z*_AxZpKTA>u2PvY1T16h5HI1|DC#;{Q!gG}w;*yGPW7M_A1#*H2O+UyQ6h+_bR$Ce z&C4zfy^e$;9ogAGlg}acv+Vn^M!Zg{W3Rt~CzV}rP`8Epe`rQt@1MS2u!nYDDAGGY z3~I#PJL9U^HQ1b0TJQO$YUiU=mJ%op`}qR5FpSw^ul`7rIYu=PWwHgmLz{H413*yV-(UqIzpfQ(|hQbQTwJ+ zTV9^W#qx1eW0su`{)pah9t_Ajp=agJt6tos)+i!a1s$jzG`D3gcs&xQ;U-k4!VtEOtwe6cH1ZP$J+3JkRTdm9pPAv8{QRX*Q~C}`E0|!d*HDe@*cdW>wL+i@(T{RRsK%)j zVYQqYsHQmn{C%d&icih|(bz3Hq{SfflI=bJ9Dtl@FYK7g{1jtd$e{d}YY&&-F$=6- zoNvxp;BRX7ZEvPIMB;E)B4;g#{v=dKW|EOI_|f^X1OeI)+A7-vQ#MSae7dOb1pZdKBwK^xex6~t zWO3x5v!SGz_h!xzNX_Gi;;}moBz-mVp4PN4Zlp zorT$C+*Ym?Xa~@$DNER`cjmiyo;a-ivg+Z8&-BjpsCHf|z0+{Afm$%zu{~87{vTRn zP^J3A+?~wb)jk$prm*XLq{1}&ya|(EVV5VwzB~VVXrJ(k&~y?R=%y#*+e%Pr{oRwS zLRdQ@@Z;mQFM`5C=$S*S7VtDe4RHqDV2#Fr=mM~{3-%>>;;v@sJaR5St@5@=F5HL` zw<5#vT3zJYrOIPzrmUpU9`aM))jk$kd8S$8l%VKg=)B+KbYN{-+zJq!sgO&qa#@5f^o%VUlT?$f=G+QYM#KnJGD z3lR*`?@RUSr`l1R9Y8O?RcL7&i2Dd;oi);Fkbw7blB)I#@nCu(hk74}maB;dRQCk$ zxdzzn^Ly}{H)f3yqs&MbNX?V>Wo>&k9WsG0pfO2OAK5Kc`cR7xYf0HC9=!t)<3fil1jQE(? z1r{J%PQ7P7s(P~2dbO9ZB~dj$$3cpTPRs?yH}16+a|+$o1~eUxq4QLK$H?mh%YGM2 z%uqjS5Nt6zCwxZf*016stP!Yn^_1MSXDo$V<>+X+9Qz_oil(>AlU-`;mm}!`Fsa$$ z6!;7qZCy^NR#DiLL3`DVNU?ml!FGtr+e90XJpTgNvXc{T99m?8J6vwVOM+ogI^8(?vo+f0IQ*t0SbGF*qugyi$p!g~&1AfK-XiHPTj_nwczxK^&a z3YWG*dwQovlK-yeb)1HSf|483?N_h)m~~VWV{}^ z>mjzcZO)6{%wFc}SskN4$FB2cDEj^J;lydLwP5gW-4sE*Na;xFs)=|jvS?N(nvRc? z=!cFef99{he1e(Q%a1}J<7o9U5rB70=m*6DFeH`fY4g-!*Jdmb5FsYb;z4X1?3OF) z-WUL$3+eVBbyk*irBVHhQ=z@DFkf)DNb`Sq=~_SBUa`%mU;m*^hu#YRVMke&P_d6s zc}Vcc=FdQ$FwZg@pwP+iOWCx0nlO=ncWWb}(2w(lsR|2!3uqNdJ^(Lkmyxw{rc$Z6 z+f$A6K2Fx=&uW(t#JA^wz;yq~A)E@M3iKC7R94%(qem*LxfbjjF{v+->l}t0{2tzAnxu{#AUiytX@j@&xBa?6 z&a+pWLJQutGCuncS?d7=TJ)7GS6HMV(=G#*$pl@juMd57g@e7p`P>D+HL&DsFGkv{^7-?)?;(=qX0EKuWg; z%ao>1K$P4-ZO7np(e!#TzklZgBa&_=N9{%V2$scSPtnr|7O{ zb5aP?2bP<3{Wp|WF~IAynj!V3K4}ck9ur4*_s%4-Fx!f+pHE3&n|$>9Tat+p#^2uj zEz&#_#~nWyuK4}7vW@Rm#4vyUMovwrokWPR;sy`1Q^Tfda~gI2XqWBTPAi`iIxkb? z>zm~OM!<3x)d4F=_V1+c#qb~}b@m?nr@M59;_0g_j@vN=gMuiPBAqT+p}tSBV{CxL)F09mQq5bG&T}pbLHqatxZM zzkPErdPnvk_a7ST5~!Qk1^>zL?pJklZkp_N1C{v~+s5fFo8tc+52Y`VFmmaibdi({ zuMI$fK9hnnFxjoIKd0$BK9YT-q`A2m3Mv+|q3u#YHX;2gw*SsN+7nX5FGeX$a#mKX zYSoN=)Y32O@;}!v-JkTgSq%&pHCsPJbG3h(;HJD%r7(!J{q3Koqe4Z91(xYtefC0$ zHTBL$wAHb>G9Jj)SMt7K2OGapo?t!yl>QaeNk1`|d}-$^gN&!J<>IHWm(T7A%b_^w z@O^!_(jrrzd3=RtfokJ{f9`oc2NF}N;+Qf4u~;K6=@tC+?xKsyutA!6KAJ!Zbz}Jx z?RT;xaFMo8`Qi#k+N>?lo`QmYCiLn%ui1PUcM>iw#)Ngdf;UCAT2^mBh9|rtTx~5# zbHrPS)~Lwuh`3f=*)JW(q~x)vsXQ7~hq09ScJp9;qa=I}w&q9y=|)bS>yIC$34_M_ zd)C5sGMDTZ6jJ(oRvDMHNm6Z^RAa*?86XJEDVv=jR;{>oY=PC*WJF{oq< z5k&%f@%KCUadI#@^3?3R%U2s?dX@TJ?8mHE(lee8SYxy&Nh9)we&@p*rc+FQpI<~t zL3Aw^Wiz{su^N`M@jtZJKu)1QabrZRzKJ{i6cR}RMHbX^2ZoWB)5cpDK6q)$pr)+=mSYrA@qwc|u*j{2wJ zXdh1`m3)$Gh?=rzk>9j>myE{Pq1?w&;4>j_7D0bQGzS-1IBdtO zLW@^W|PGtbEZ95I<6}TWu*hOtt}<61m2vaXHV=4DpBs-Kv2eTa``30s+BD`seFo|FMK z)BL`elvOLZZP2VF2$-`Z)6GW5hn3Bex&xgS5LR|D1<=E{P}iOn`pJ2_0d6C|#{}TS5UhWofvs1aYKNs7yh>X*nh85Ha{`Zg449Lu8Ix8NJz*tm9k zB0+bTjilx0R+**%(XAu*uZp^Q|DkcQGy3g9JJc}~ciL(Ksn`6Y_LMVfz^*a7FurY? zVjgPpW4hVRlB3mUle6{y*Q%kaLkHd}dyJn|iG&c7aCtI_&J2DFb3nZ6Xb zpe1b;drsbf%ZrD_SDZnAQSqwiOPs~*1lAx&LA&?x8DkPw#{nO{Pk^OdW{>y-STg?g zo6k$hJTcO=Dx@Ej{yiQ&hM#r9Qy@ddeF8S++eGg^lWTeUZ?3%#wR{!gymaPCxDg=h zxu*Da_O=%Al<5C_L#Tf@ZBg!W82fc9)yE%Nd3g;o+3xe60B7(iu8HGIC*jj@KDV(n zv&TEd(aM>tb5RS8ru_qHw&wBpuk>0GDX&RW`K)^jM3JJtr9+X2tEeqbhFX7;rGMOjjtBl4D*AEdu@hQMmpj%?_($Ysi$b0%D&WMt|dV^Qn3fh-f}`hwT7| z%SUeOmRXUxUF7Q7NQfnB+GK6j%aJ=vTNPt6Glz!8ab|BW?#zm@ z%XSc!>34ymIZOp>&E|X=e?U?2!~ZwjaQ7g`@p^Sft&|vvVBUW@`elo3MEJRGq%R@a z7ylu*Rkuqv$yX}zGePqA8VH>wpI95A1)dCnpzINfLJQ6Aq6qVez^0VkkIf_J?1BDl z+onyei!VRpj)R@+^-9&bAG*t}2V@E_3fCmQ?H+17u0rSiZuEjL7$|dYO$xYO-ui_L zDj$XE*7OId!sVy0T0E13EkxKF=#S?dn-6=zyDqd0nV$o(Y<%L%OwVa1l#U=54&HsoWQ$cqlB7o#i<0VhRZyIzUyVY(MAc9+s z-U1R&1js0|_|TOUX7GF-^phruUpRwiYoe9NLG*nPf|0Z~yPV&N939AZ5AoPv>pwh> zOW^wh3;EM53}dhqj@8_jd@jey_Awmqe`kU&K%6M)9G!sfFLkjR{Uug2T~h3G=>Vwh zZ+=ORUz>INX`gr;xP}%iotrywi-S}GMtvriCD)CIGHkvb-!0g_DyJZWtW*=8nQc6p zoua%ShdSWwLer%)(K*iOHbygsYu|77aQjX{!|+;3YIDdBi}N*4r3!UFc<5Y9ub6AK z9sZvn9!_)jhV|XaTIS5++{*cGJ!fkNJ*S{=8}Zit0Ys(w5IaL7+dly9r5Rn`bRFT83%ahwKji zyj3yu1q%?x#77eyX35cVacA#mIVN71H{f>vj#&@;Oi_k~U`P9eWUIytmh?J7!?8cW z6{D?v0c^q)s+iQ+Iq&L(=@t1N(S0PSyX&~brY#+Gcry3Np!&J%$>${ZzlsToGt!WO zAFR@cBztO!erm7pU8m`1-1WIzlm=(KPNnCJ`es}Epjyu=V)X;dIOnuUO1x@{;%y+pesx!6=@?~v!E5E6r2?&OUgZ=eUX5h zxMJ=GLjCgr*W^Mmz44p31(q48`fL7F2VkMf`{Iu|{SgRHDd&lf3DUGbV4iAmcb{nS zcbNgCU3BYi?K&#+{axGQ34LzgWbf>zxAisWGU9T|oWPX8Ia7_ydImxEIkhya+M4dX z>Q|m8I5#fmZ5`C{bS$UrLm6Jv%8rJIX-j~_Zx@-sNC0wiy9ec|(~wVfi_~0mppEdK zck(!GA5IInw}J43GCxb3p|W)gI(j?dy9vTyD;Htv{)Mo87`bWUIL-^|S(T-mV{sbR zGGADQ+D29C8nRcyooshZ7v z=9GtGWl+(u*>wIg0@El|8~&(Mg?b!W%4OH-w#Sc|S8X9c>C6};UO3?A5|hao&>fTD zIbhfBn7?t>p2g4SjV33PQ4~ezV#U`4OKPBox@1_3YMHQ$xCyj(x$48Das44|mP+}d zME6D|uaCNqje?dUdYEQh%rmOV7S*ey14H*jR*F9%C|WF)Qbujj*}{(6PHil&-}qBy zp^-Ik>%P;Ud<^WtDv2#NHK!EPXZ7WmQR_hOFnaH|;rz>0xihNcC4UY2@VAiDZg7KN z@|DRTNpKrt?XE1_X{(r&RJ0~A;D5z|HucZJg^kMF^X4{t+AR(m5>J;Y(ztgsN!SZR zs><&G5&4+fTtn3;Y@@W6gvnzBQu+|J%5zxOz0yfUN#&Cn;gXRuEQG<}19ufie zF#o#HhA+;mtfgA-oK+?|fLHky_;-n)Wm=_oi(Y3!WNUZ&4-#a*7KMboF zX{LC`=cLE&UPsV@Y+2ceXz(DMsNA%tbnV@;m4)DnTe-#ZYZhvgH?JV8=a{G^;oZyQ z(-;1%G3E%2k}fKNqYUyt& z{Tdh{+ok_{N0k&hBdFFwdYFvleDb1WGCw6+Oro5#(Fj2A_e2a;WU1ucJQ-)^?&pV^ z=XYqVwX-Jq8@~~(_sWaXz9YjVtkGITJj6?dNNunP`8t2#jZLShAh2NrK|VKiZb#Uu z!@^q!+5ZoX@0*pI38~b?f=m22i@p*qdE@GGZ0m{&fD)X18X`e013#j9rNt-_edvGM ztD;ztWu|MY1YL_IeKf^_`pm3U+kAlCY2~a`*do|VGp@o_;7cd05mrJm$RNZxEXEJo zB}5+ytae6t$K{%uvA0(!@;T}7f^CZ~$&;QjP3hC9t~z;m$1?zHy@c8daOov>B~aJq#%qbv&O6df9)QrIo4aoWEH%=jr7J@N00VhKyT zBP%H1d=*c*T+BxC{mY9(^Dl{Pq7aVf-h{7~m3)P*dlwUg4^o(r#H*QMrdz4 zMeUNGG<==9U%sRF27X-fP#Y}Mr`H)GXTn~M__RZDl=(W*hdMV#y(@jJ#-y~TQiu+B5mdGS zniL;7iLj3e7j&doDTM&we2;GlLT8>j5!S~CMm%XmUo#h+_)aZeg?~L*b~YA6>$@Ol z@#A_N5|1%lm$UFX@x`k}<|1SojTjNcKS2#zuVEZ9%S|Qv z)k>jyo`iO16;$6XFk0R#%Y8}>QWb2Di@sTg^ z17O7461o_-*n+sn*CEpWiQiZO_n<|#mB!eqaO;g;CE3FUsWA_eZ-FWI;Zt~Zhfj7X z^_OL1_4Y(rav8umtp?zzYc#xSNSr?+e>2Qd7b>LYg|#D^hU$~5U)MQiXOj1WEa!_} zfP3!-JjUY7H665~1B5E{%V#8e%$Y~HPb4uUvzw4q?RuN?cJD8dDn+KLuR-h0lyjrDL2vyx$`qf?K5Yp#Y_e%% z66CB7Fr+T90djljF2wginTL-r!IBP9>Slx4{Kw?N#2yv@OrqvWe-MfO9bxJHzT9@0 zfiv{cnHFcnTQZW1R`eauQ>l_|%>TMO4 zw9J0!%g5NCv-*T!Urz4m^c3K#Nqye?oP8DJ^RE52fqR_MDOQk4i*SH!5-lrJ7KaLh z=*Xsck@uSLuWIw58SorKeLhZx%9QL+IS7?ML|6DvGj@AVu=p%B z+7e26^`@Uoo>JKOHIWGpL$ZAey*d5pXq$tr?Vau=KSRrwP`R95CZc6z(`un*uObIk z--v2K8BUUpdSpwq7_WW5oFr&+R|4N>4pU{4BKT3g_;Q$(R~4VkPi@B)$~x)o#IQxM z*7x$1f~IIbw>ADU*)N)t;)I}np| zd^7K|YXD)f)^6>Mzk4g$_#uVw<*`+9vW10~E!JG;>6RM%?IHFb+@C<+WL<^+586n7 zG$Ix}Fk&XmaZav3)4K5|IU)1e5FURzD4lbd6c~H7&VuEW6(ay|yyITDFX`X5X8W>s zl#t%};+MGCytK{;gOftuxyMsn{B}d;zb+wGjz7H?bYt91BKRP?#}(=u@uah5N(xeu z&m|coTC6mOb7sfevAPURbNo2{!e(!tCF+|T5gq2P1a|@$)FOaspJF2^k_IxryQMj= z2Icc%$1IuTcb7CSQ2%6C7%p06qyBS)U^b@M8-EOGi_@4ARs$<$s!gqSu8$3d;YTe9 z>*>oiI729&H zwC)2g#r*VJ9SBjtAF{{VUBL>L)dZfh^ z=qDbCpzPl;FbTQ51`Az)VHBk3?Dw8jxstViAhFh0<+G zgn2k|5nF|;c%0h9PsJCgOgI+{oHJnY+zNe_ja7NY@X{p*$yHuqzVwsLSr@faq)OV=PSEgA+2j4`6?j%_@>8lQhQoS*kN5yM zf@@OcVO>A8Du3b zx2%_`%{QHvdCc)J_kHB`riHr#`S%L~bPD&y0!GjtUu0Xh^{RV|9X0u-z0Xfjh029tGz%mGUaUbKU8|#<)~NQU_K?f)}x3j zYi&kZiG00|Y<6-WXYWk85T&d?&t}%^Y+LkwGDQ3r>$*T@S9z}-uOm7ht-xe)v~62I z?Ni-czuPPiVepUCtpy3zYBP97@-@7$&yUc9J>0vurGWR~=GtvruT+|r#o}WhYRqJ< z(gf0UW39z_jlpQzfa+*bXYypWPjR^&8;&I<@slDW+aNaUAPnv20#aY(L1MLWvg&Jg zjsKhj+tZ(pdYKm{0)LyWut|#_aK{p=2nZPBxZcds%6w>eTm2*43QvUk)enU18;Is7 ztGN27n83Khwwc_WG?ftCnjKoLsKO^L2GEIl7~Yt%*IJYsY=k5vs0&+<-=8Sl8t z*02Uh2%pV0H`p%9uxV9_}9EB;I||3Ij6i6L)Nx8j)c(JK!}_X?Y4Z!yM>lq2i+ zy8eTfS{iXwN}r@EXV zZ7r`BAL$0_K!Y67u`e*IW$48<92cMth>ks(GO>$i2 zSFHY6J4sSL%tEs69N{d)JwHV@OYUuNb3`h|m#9jfCKs!3*z5G`)?q`n->Wr_Tu1iA z%rB=XWUFobc-@UsGMFsMa1J4fH8uqpIu4F`^`CIoYAwGn5~q%GfH2=XdfKf2?hgnB zzf5)PB(9y74ft$t8Nu2jTodE>DdWyyG*9;GEWo7ZN1&geW1P7hiz5A+t}F3BlY_JZ zit|Eh=*MsM?gqde`S*jwX>4CcgvglFHzG&+A*K?sCz0goJNy&xNo0_Oz@%re2%?aYRb$@U+bd)u*C_uP88;gfG3U8{6a+$fX6Et|FjbozZgD@E;ut;qrTampWm*WHyNvT=LS&M9!ZVMu zi&?UDtlWB=o$MwO^CPTQC_a0}$z$4|CF66gc2dbCZ{AiLD_*j$%ttM%o>gwtlIXXK zEre^*xma<68`4f#U%CR-wft7+h*$48%a-?j^(ukSoN&ENrQ-Kp2P(6>yZXAj8nD>R zoFTGT!LT!8@vK_g9--Wx<)K<{v()50xR#{O-89x=ju%%Ab#dHyht^REL1+@Q^jL@^>%Q8G{{`aWh5czL4pT z)G-BPlBK@=r~;c?{it{*nx#XMYu^qc(LK8G*-KO~tzB6+NG8NBVD@TDW47uYj8~w@ zV@pn(Y4!Gd6ZA%x?f$lezc4W1kNCb%vb#Opy0lO>&_{Y({GH?F+F;o8e>K_7b(1mC zS9pQCrC5oBeuPA5X<99UThhfF31~hzRH>Ym52`jms!_cKW_k_zXO*C~y=?vyox{L{ zSgqI#73fhgW9q`-^Z`u&+~0cfC_x<=I%|*`(jbyq$}Azhd|H|tGLX{wVoJ|fg5Y~; zAdt(8b95ZXV)#F_hPUOD9esV5$Jp(e!TW@#F!y;!XbdHktwK6lh+}kaBALOeFWk#1 zKg>eV`2x_O)_6?Uz0|ZGKP^;mRBa<@B!z7qM(UQA4WWQ__UyZKs1|ec7F{a)MxpP< zTBsv%5`G22YI%>0JFm|V(wjvs>8~&@K%)S*j$s9<`eRboks0Ha8`Tr_sX$iMuH^yf zHl^&9j#%hs&cu;7Gl2_t<%P}waF|;xe5KO1JO=Syj<9-HO7N}Ydd1jou^et?Ixe1^%}rt~X?F3X21ExK6gZw1*%1_8zKqnY?f~F+yxKQz4FN zb%L_`-Q$8z?diC>_ArODTJp_*L)7vyY; zehMlz`}_C~zquo!7bolQ+qj{Yy-&MqJ(8P^Vl+v~8Uz4d7d4o502YQ>@;zd*T9gaa0G zQ{3#3JchqZH9|6fejBm<2|oPi#Rxx6`YaQ#KMpsXX|Y!PgquqHODB`3y4Qq2yuSI4*2)HU1pYkGTZWeBVeDXiPR*U(?|fLz4Ht#@-OyKc z;dh)8Igd}UKyq^EWt4L`g}$~^+GPAnRjWJd12`xA+yyS#5UgD<+FqkuF7W_{g5IMr zb=Nc7{HmR>y#wKqDt6zIJX=|p=EGS1Gw&DPfa?C)*II0E)~WP6LxwN>!#077AGb2R zJw?Le&)w^Y8efjPn(1$>;*W1I4cTne>cj*Irb*x}T796tI6I%m)n9f!XYh@HPIplt z*O4!p{YEZoFKJ-1!F(p8t3 z%0+lMpD#F53&T3lZ9?@l`$N?tLphK6sxt$1s!pP34@vc2BS)e%yce@t{m4;Q`9*0{ z@iAYtVeXvNG4ZHCPa4b(c>nt(|1qquMz@V{I#m${z&qALa$_DfmT~(2bGr`k4 zdbGCcH^IUudWq_qKYU_ULf~HqO?yTMo>$C2sO_05Cgk)ttg&m`HYw>8cGVtl8X_Sc znkdj4`)lwwY60&}3$0&?4kS7t;J!4E&d;KPgjY%PWln+Rt@Cck#efd+=v{ZCsorWp zPr;-H1h0KB*CgK$B|f+ABdx`m@oH*Sysb7F|9aurOVMM8pd7r>h)}N<(qp-&FT3I> zDTG?Mk1JEYQ13dm?!5aQM6gA!@4T?&clvDIW~RexL2y&?-T=ND?i6SBH{QZ@t}Cq3 z7yRe`s@Dqz7f<+#oVvC~ltE5;$D4x>PSs=ffkkEZjZ^IUWbm(HC#c~xWrXFTC;H)? zghXcPn;#N1K8H(CYZ(Xt6!lg&r_!1E*yI-9*>qr?_pu_DRZo&I!jef#uJX;85Hv#((NA(K|P7NhB>sSBRg&k_mR*1=-f8$3((J?VN|a;%o6 zSR6V)jM~=hBO70=e=y+#zw;yg%?PDa8{pQp4@j1feiUVx%DAPzPlR9xKN1{*43Q2f zG{cS(4r!T*j*;vN8GC_z=ga;FSW+lRyRVmI{!DNYguHpR(H5%Hxc-4JKsW3S1if%z z+J}Nrv&;WN8Ybfgn%^^evf??WFKQ0qZA0eOyHxnKV1WYH1KvPX$2-p>)g3aY)btup z44k`yTCzV{{$jCtQdG{ca&gQ-|rImJDVNZ+J2eDnqdO{_*H3}Qw zL;R;fN#cy+Vq$Bz9=%LjzojL^Pkx6>OZXd_ak*sCA}M))&OVQcR2@F07Z0oOmmjik z2T0ugG*9ioZqVSe3W0&;SnKUvy+G#grs{_7ld~}^tn@hCeX31ICt7O6HG9-WRX~43ukNqT#{%7CFZXd@Vm2mIE?l2?$F;+<*X(l%4 z|EQ%lNC-AP4+uR@&e^U_Tn-nlnfunQ_-_Z%xXHQVEInlTgV?e2E67HbX|#83%wM{W zf_|{g96dSMfS2(mOqluj;eku-kfuprY=YRNphrX0E=xPW@9ZN=iCAseNLsDh_--%M zsmbIzPRa3l5#r;(Kf&qdsV`5@N@_IigcE5!D~x-!CrecRw}#{SX47Q3e1~}Oo%zgJ zfGi|Wt$U(m_LoA#K{1opYD<0XlhqX?Mf50EZN)jI!XG&M%tl+s+vHj#u3YWThA(F2 z329&DUO=vOYfnaJY827>BT1`$R_S`rp*!PU9!A)2y)=t>GZN+8&zr_jrYmeu)^k;W z&&n&DF4Jir6Yr-qBs2BH(!+MKKVjJxE~eGZlgO?##6MJ%6$}uDYcy2F7hs&GD|BK^ zFw&mFX0H@&P{&c9+48-IBv~9(uyL9ExF|e+{#8W3jR|;^ndMb0goKs zt9jy>G19Lfaw@@KK9!#DT>tPp>lxxATc6!w8#`@WqZb516~@-a1QP~Gh^c2a!C zJRuERzBb0a=|x?h`+yZ70)9=7*eJ27u;z^-yq|3MYMIGP$qnE3$H`P523!yKCHb~M zwR3B~vG~X=@jg#wG2q?1@J)~@Z(MNM6X#jv1xXx8$sCFmU27K^k8%N5MJDW0$xX&L zT*)dnDiIUm9o*c|E^egR*{5#p3Oli-$9In;*Li);4OSbJfA~>*)D&P_$eayngsg)+ zfR8Il(T0^Y@VwNx!0K*0O}8yx!HCy?kvHltp5#l~uvMbk^?n_9!XyZG5sC4ge{ejm-^Wh=|w%0L9*&hEP7a>G4c^c=!s_36IWKirVP zb5w+4N;UR;j4je1x>Ws^tNTb+J9EK+!gQBz%{pMPng98v zG3+;Ybvv>IC1Nbf+o=AKFLd4YMGpeDve_V~< zKKK^9z5J(yBq^Dt>PMT&OD~6?+(v{p>-UFe{rSZAq9{T4;|quH@6>>ImV2%GBt^Uh zrTcI(yB#KJTGd*J$a!s#W*6AD`T$wo!E$+gluD_`L_JNwzy6nR= zpUP`*tF*8E=F4Bz2kJ#gD;|nm2FCLmk#s-vPk7z{bD!r#W0Y$fNyJ z0Kk8e!$oMGH~0Mt4oPg^tVU#O4iRigpQg=Qk93vT?o^MrYZT8PCy%^gECkJg~1V{%t2 z)W19QTM0?aQeSmtj&@pXJ*akM?$x*;dmp?H&wJ)wlx;R7uA0c+T~Vc6-cwcw<}MTc z#sTBhEKoTul;~C&20Qo5SW9+vbqdjCjngw$9jEB+|_}+k5j&B4hI;CuAOR3Q~#E zbc|d%G@@Rj&Z4VaCw9>1YpL`1P%PN;eInTx8C7XmV-~EYpqCmtz=q^nN!iE}U^*js zOUu&tQ`Q!Ck5!zbe&ga@6yJ9&B-mu6$uk{R7?Z%b^u;kSUrq#?u)pKh11uJjLpesZ zSBYTFb^~!I-K*DuVJ~>;wQ6RVXQEAkg z{4aT1Ha6zEEqyl_HEI@^zi*LupL#Q9J_R9`Aum^JUz=tMq+DFFVST6YT&~jcr+t1V z(R#9KG)Q3o$#7&;9Mr8d5dxQiC9)}*4J)y-e(%@!Z5#~=8=(I8jF6hKg^V!rWCuM1 zG97!3;>YpMf4b32{XHz-Ir*&8(C76#RIoyod<^=_81YYmYJ{YM8N;>8jwTgBm4G1z z^dZwBk@Rp4hmcs?w1?v<6+2SfQGcq6E>OAgt&5zUi5=G))jfXhH|@_ObQrl}_V_&k z#_zXRrUnY`&YxAM17#xSjE?~PFv|nCzO_eeGeTh>L^U!!Za=X4QSEl72X;P8HKHbZ z3J44p?f(+J>cuKqMKr$jl`2(VWZgiW^{sVW^*YV-tsxIS>KLgh?gUX&0!2GvCEceN zMDyJ>_`CK*$LD9Cx3@ra`v0NX|A(f)?ZS399z7R~w_FXEJ@2yrMtyA8 zH5BY8eg%VZHlhhGr7_)A*Dje9EWlvr|BtG#j%vbv-$oHoS`m;IP(m7{V}yV-igbx| zPP#V`0i`D0n@G2GGZ2yPZj~5a8?mv?cfY^BpZD*bvz?uDKhJaD*L}qg;PAfU$`S{` zWU6SzDlh8kxckF|xPtynGikmzH`_aA+May6N>6lLWY8w;1FE?ti?@hAtXQuEST5-5 zcSa*Q5EJp;yi_pRXzn3?_$#9=PS+oJW-=|~IU$;*WLs=`xyTj_3ARmer22PH~d_k>P5v+GrxmA&ye~k-ERW$(iKtDzY=i5YTxEs+GBnsFp6De%K%MCzXr1 zFL!HUjjUOQ7ZFYPvykGyAgd^!micpwe%S2#_r+ri;8#T^KbEaLcJ|nSnwj*^ofNl0 z+gU-tpG78?x|KeStsY&~b1FMC(&lB@TN zXmv(B>SEmdDC_;2j0z3ooma1)jOlPXwz3@d7k66rE72nR72^h7>M-d-2-b{AS~$hx zU=rnu;ZnkXZk52@kT>3mS&*~8mtXy+jaDKh(VfbVx#()?en0GvT;vMaa&~w?N;!2M zwZ?l%i{4IRNl;jfGsCx>Ov9(bSHq(Mnw-1cd%Sf^Q!iiPy{Q~gSztQ!fgMf*$FSzO z7m}3t^@!nkL;f=Hb>r@PA2-fQcge+kM4SaoQHBG&<)B+K6m9Jkstdm3jKyFy5y1gqephhcr~Mb3i}P;;Yj{&MaXQq9O%Fu zU>q?V`zlHd*gove>7}j#7)2k^J+&7){wi91IiR6V%YrAmY=-|~&Xsx+lf58PUrG%n zaiM8-ZV;u=d4Ej!LJ5}tNy$Y|2~Pf0+id?Nx3kLz=!fR0J8 z&AZKmXtCLCWstPoGI67?RQzTZq0i808!o#?#VCAwl_9v|1bOqT;)<|Q?l9$kG=I=O zj2w5l_?^z2$TKQ`d%QS{5XE$r;a+^+iJD&r-x}@W##n-}XIR~{xe*&)92M;{%Colm)e@4X zdX(Od_fuqyY8Isn{v>_Z`}tzltdsdSfkMahpW)^tu&~}CezG5%C>{hUx%Y!ME`{xZ zIoEFiIFIt-wrK}lBqFtDxJ9?p_Dil!ZC|3_p(uy!~CwOqvHQI}hwJ)1?D{ZpiTGwZxMbfYbPV7v0y zt`wCoNuX>JDZ%T~m0hL3{0a19Z7tqPnMI0|Z(R~K%OyHKW}{JK7b-PoUM4jaji-Oz z>1q2>`49Bu((vW&?irA(;f8g=+b+)+j(FV`FXa&l6pRA`NEF)xj%;kH;T3R?M+dz> za0I&u#E9&O^cW04#O<@KsDSI;AJ@C~Zptx#TG0~csb>`DfI$o3_vUslOS=okuiti} zJf7{7m}@tUQ!Yd}@V<5nH{HAlo-RlE zQ8Pdx+%ym}w$TeGuPX@=nS~bt3K$MGd#+8&3lLex+S8u?k`^UP9S22 zA-eugzM)NH_e`G_95Lh0*QBf9BX|ZZ?mWho5-2^rNy@J;cGu+}QCA@6F)ZZKw6Dg0 zO-wrGVuwX%8M^%+wi*73O3S?qr}cR7t^HZG)Hu%P&H~TbqmKawsiOVQUvsH)3|5Z| z$Qh{}9=@SMhFqc;+>+8%VIEvzAbR7HIrBNB9ZF zzNE_~*)8YdT`F=`K5VfcO>zn6Nur4dHC32fa26fPX$}595VUP3xNf8D%8gfn;$`;i z=I1<*Xv|UJ1NV`%wcbE8#`M~aX$T7W4X+KBTNem(&QZZgEX|MDw!;I#!Cjx@KxQCj zFaQn<-0%aYC&W>ARlMXZv1~}-;Vo56FMaKsTp#_$ym?9888tsRQsRdDLiMRlf`^XR(HkMo>8wwalkU8dhiCq$Njl9B*HpJcdr0dA`OQI^)D;wIUa z0mvfA&-Sb>^!2}63r2b>wOk3+7yk`w?hl}e*&IE_r!O?-E=hX?j=0x7HHbF4_fvsp zLd{RkHXa}+e)7Whbc0Rnk|BNvB97s>WSQN_u^rQll!8swF2Xe#UcZMipsgGSJ7}GA z!BH(GJ(`Vf&75uO%wqiS%A1ItTH{R%y+6tO(*}G$%HaaM#oj-ec+2{Ot#d0$ zwNB9Q^AkM?6SeN=sKv})cfLV}U_buYkDh=+KnXstI!fMQSfMw<*^Yuy!gMgo%!>(@ z^&td+(nQsw01H>kJ)S;W%yF8w9j|CWs9q(&Er9f+|H>-UJ(A$*`{D;k1CE zCH&34HR;5W!7_M*!zv!zjt_@JYbUIwSD0nw%mq+W%QQv)7NlYhm!{uAXyDjX(-9%u z<8fRybLGSIhyl(Ikri-X@lB!T#=a>XD&mmdxl=$Nnv@#*$GJ4;l6*%T8IL&9G#X+Rjn|c*}tcc(V z=kbq-BXDEgc2;{JLII#p6N@fM1kD`_Dp|$;O8R0~j;TqIvHZ9_{eD7@*kwpU+M4T^ z_EAfS>W%4Gqz+BgHN2l4IOOudvE$i`a&iSRPhFokCQ0-OvOjFq6It$j_)jytz4s}D z;^&tyT<-;+7NKF^$dow;7msyB80vpKKkW_?3@lgS8e!>8zGxW(01n@>SyrXwpcNFY zy29aFpiX?6OIujiBUr9NcKY2rdlJt*{;aTrHz`H@aALT3m+Ld4F_C*~TcpN%tuDu= zMK)Fbf}*UwsN{_NyIz{Fqw<5#VS?M>=iMRBa{=Q=H_`ir+Z)n5vU48l@zdS7Rzhwl zVtKD{!%l_5Zc&6-nUu9JL+|!HQldtVep*jN;8tZwELcRlFi|$JMPpDQcw5(ir}i$4 zx%_;FOnSWO*XFjV3xK{ylP;Nf@5G=4Y^REY=ztO-_yPiB_F<-n}i!cdMVkVCKyQ)dHZwM(c~ z1o2R&_h!+bXvTuQEpGkxi4t_wsQ-apW9qy>Q_Y{o5ad+x*@V)Lq(b3Pw-~b9->@oG zVn#%Pz$}iD9MSh(dXW0|gF`||Pzc|D+|{%-OI1yx%s42{jizq*a=C%IEYieVgD(XS zUj%51KJL?8O&+0qnDgY%+XC~9&|N!|C~?8RE_&wn#xQ1*X3q;NnR-ueI#S* zhb2XkViQuWMza>M*Aede>Q`{@3aM#o?!`J`WuDbJPA&R}if-yTRr}3jWC35JK2W+I z`!kjbYsahD4$_V4-7 zC3K^C<9cibMw%iEN3Xq%li%c5IR;yG5j?YEdRLgYKF36nv{~Msyj~8_KLg0e%p}dY zX9`_S<~GNFwY+5qbwiHd+uq;{-brNV=L#3cwt)I+SU=*UV>2Cu7AIF9$^4!o&ic>g zQiLgcSTJ{bNLLqM6H6OdnmE8Al9|Qg_=K8xnn(RJ)zUOGixODszV^%a_P-#`dPCTPFZ>MOl$i zD9=Oy_=WaJ=S{Y%CvIfH0tX%=^aqnH@@CR``;09Ah~9o}Wau<-MuC1hIYFA%_@JN> za;q)VTZX3_PtaCsvJ1IqADC5cnWQw1mKx*U;|cwO`2jqg119O(cnH1Nr!n>lT(e(< zm$Gb43{4<>(fel_x%-}c)LIbgCTm~_{F~yd_OKDx1-3XWuiz*FlA&4NdegA4r<7?U zQm|NdeM)6HDW{MU!X7VN`eNiXOtSXHfs!{Cge@lyzvw#41r|5G?)`qkhxfsU&R(6Y zK-S<>yec0GwLGem|(3x)^=zoz{dETj&aPadmjTW z0P~~Lkv6kl;m=t}kY%dsryCO!WN55nOBErlrqszY0H}pIp2TtRjU3Rh!v>kD2`Y(; z;K)3ua}-Ne$ijB^5sv!M(%@hCD=R3rTPEYy`;f3A|xGdwC*qu$j~yq;4~d!aELE> z_eD;hug41)`((h@iXCw9b9J|fZ~o<6WZfFqi#l_akA49|CY1vP){1+WmHo0F+|ym} zbweZx>r?R7ehic8EcH7OaC2>=TwH zivreZOmq01sk>xDhv)XnRi*IrPAIszi+Y`VXB0Dyl5-MCo>W~44?RrW>Dc;5qzGMW z0fpTlBA4ezg!>&lFpsZ8HcFbNf;X6(%jONTN2Unw8{koPj~^1w_Rig2$V94w#@72) z0dOsRBlrcN(!P@$y_T>nrMFK3>_V@_z;)eD$Be&C-aoc7){N#lc2#mq@Dz z^aF~jL$beZS#q&;U530jq$z30+pRqKVY?^HJTuYZ%GMlXVFOY+bFW3DE$a(?FcGl; zNuZN|KMlXA=~6g`RIb&qyJMHI5oeY7Mw}Av2>0azNGRGz0L5(#vHI5_ApN`SkCP`M z_v1>eHPH^O7FyvBO~3xwOBYBn(*IOXZgIEdX)0o9beHF;bzy#1ov}%5@2I4E3eVZQ z%s?tcNLK1P0}lKyGZ3cdrg@c&Yndiq`RUVT5z)+DwrnJ@mu-Xzz32Nus;=4NH{zcd z$JPg6Mg@-=ta0?a`Smthh)xQwzE1cKrFPt%U=~jAra>Rt-BfEr(vqwhF}I(S8S~YQ zMC_e})i?h`ShP)R_b$wff1AdcDZjE?eGNN|Cq$PD~=Wrv((<+?3@->H4h3 zZI5t@H1?VXw+EYUL{>$Hd$k z`5{lO-AvHHGf>nO&si=SrJwIOT4!-Me5{ool^hwA`Rl$XJ|3lqj{sk!VMwa+AV54U8rCnobkLRb=HQ4UcLqKQ?7gbvu_!Vz zn(5X|erP0GlI&M#-1_tBVij%qk2V9{4?ovU+30UZ%MtpW8(jR}6P7sQ6U9lEZs^r5 zHy)8JM{|*hwv&7pR^w9uAmb8#D7|O;t<7F*%_C9ynGKI!nszHjK(oa~E-|BAHQtAi znAif*Sgr0hKOvk#iFE zw~m{9#_Sc$$*ql)QN)n<)#u_vldN}NX+F=sH8&AJfH{MIMR4USqr;mF#mYWP!A$Tm z_`mqo8xC3IPb#K_l9gkarzu=X)Yb+x=x&<u4~$= zL%_zar8>>CiM;~ym3ehU&eLBQrA(1m^#~LNqC|4J+nL)?EbXuHhZ%tj!rmYc%ZVOJ zuAE!$4Xjg{?BcCLPnpUS_7jP_Ow z4a0YiHfKY|z#>(i>(y-wNUSaMPp4=VV4-)wKd<`eb9rE$%~3$eacWzYY; zJ}H@p-_xEIp{IY5geKp~W<1|=2}UOS@#&RBXWe#=Q(`n+9qkyN3a*8Nm16Pga*Xz$H$@at znQyc6MI>*+E;ow(w4TRB@G~p*I}R#1Z%wur!=y@%x*MB=N5&UyErEH_O>1A@aNc(j z`5|_0%N3+H_9d$rJut2qLaaB8T`|9m?ZRp8gBNI4VUx^=^dXEpFvfW?WP;#5^a7t1 zTAzN+hRw!v1REAeNB6aOcC6<+c6j0=CpG6V%}ds=W1Y;R?`+SrhgvmS?za{@+oP<9 z3oTmQNT2yX8e|iX)}q$^T}uv9ydFQ%H6ofFXPfLykq^lcO8Q-oQ`Et@dF^!PCTU1O`Y-%H?{9Xq6 zbdblkj{aJ|uWb75uGBN!1Fy}!eAReuf}xY2nP~=g1Obx^CXm03`*J1u7r05t#pwpB zNi-Ko%Nf*8qckBbHA*sr*Ojo(|EZGX{d-GeuZLA1@{Os#oqbQ2m&vyj_to-lun9x1 z6VZT&NFRhD^zq#~;Tda#AFz1zfK^MG@ibA`I+Mc6(VF=2B za{sbE_eBEF7<;09Z=YkacCl7__B=vU&_c7oiRU-^CV$iHHN#m!2KaErl2vcmee|<@&yZqhsQne)<={fv zF{~TVvYw1|&PRdGZzO`?uRB>j65xq~E1F@EZ5VnKyHR=&06pOJg2tmR=f3V@(z`y9 z2}?*|Ern|+D-qB2YfLSTn-5JsM>&}Sl-<5plt|{TsgVq^Pt~L+&`?MDOa29ph7nKW zzd?3r9?l%&V-`?^;3*}ma}D{Fw~Y{2!t4Z}XFLSv0q(#lz<_6{D(&w92NV*;wD2{@ z1dcU`&XiS=F;z&Y!NCOR4Z&vm_5@PC+)3p*0sIby%vxC9acfNGkk}Bu78pQxwGXKD zuQac6IX9YNc#`E0?d&`1ED{V-ncGy$snhf>@!@`56~D%$vhT)9=DZhRiy;mnD-4%) zshqA3>53IQFHOK^#_l|n3pZ2$@Js6-Q33_a#2}n{*=fO*t0Y-W$p4XpMt10y#@fxq z!2h}wEq*AxX6HSmnM?NGU)E%zU>RY}WI1k$Evdt@B!7~nduCysmxK4S{jb3CX1w}mVCG-L_(dPA&@nf|k94(wh51j>wB|UlWL1D&I1lrk5HRtjUwTTB1+^yY8b&`aDKwj+f5SYzUWD* z;+RF`+PJuo`0kvS|LdYuzJqDLLT@f}!zUz&7&0r)>XYuf{G3kivfg%>5PAd85!VGy zg6jd36MI24G^LjO*Tvv2SRWbkUEC56l-N+p1fcbGOq zNlfDVuX?(A;B&d)Iu(8G*av_Yjtoypzd!0V@|+H-I@^OxZA=5Sw5smPX~$-o#A8Ro z&bIS@bU;<6yWBCEhlS=(B;?zZfLe>&P%cN*ItuXiJd-DSI#~gyFeY+OKTSMI?{Km_7X@D=mAD* zue#$Snvv?e*K+0U=e0&5oV5yQ@RJ0W%=^JlJ-SvN+jsl?der4AYw$(k*7mS}s?ADk zwa3kTq}nM00ZZ9W+gD0Gps_rblGiM#GPmK5G_g~4@|JQ}c4W!fF0`0=?9he=SRJ&I zA!v4N_6nxs8) z_9o~qlbdxH(xAV2g!Ch|m;8Q-D{zRiDI+%$!=}C% zlk|E_@e8Zd)17Q|){VfJZZ|ZVvmT|3hAIi~~L~?#p+c7c$~<{e1jGNVN*> z+Pf&rPttlVq#JI5yLzsN{Zw?k0pf^4 zZ{Cz$!wC#}>T=8)P6&@81ay?nKNKMXsjK4(aj$#8=>~rWPXA6F7lQNG-_PKTYrdPh zuXY$dd-_txuBbFmV?c8xJ!mN|DDU0PC8bITo< zzK93t@)9y~`{v?n;_Zp`XBA<<=szc8K$gU(c7OseX7_EI_i&o%a>T60v8m=WW6kP- z4vpMqYu^n;r~lh~rDM;ry4b721C0H0Y&XCGH)D-_WNQ(6Wj`X`A~M~Xi>~`!l{6Zj z_n~4e=Equ)?v45UGs5DYquF92fbwN+j6up@z{0x-3b`ZqNGPJG+kb4uaz?1sueu#! z^3yv`h~w@VIII4YQ$}28Gd%nQ7iIYvmC**~05`xsoXCh+unN$2FWE#Q5wCZO{#P6Z z`=?HPYdO)TY38XleJPKb2JJf>8)#mJqxDH5-V7|>(r7K5sJ|d-;&OE~P$&%5g9$SE$cQ9`_BV`F8=@uaAb zS-E0(@!~mH@zuB)^Q||P!|Pp%DEtc+F#d$}DXu{!M;KJHnf?>BTHWq7DgRj8=k#yH*_;;PT#}NHD z3bux*%%ae-5-)kJr4Xf+ul*BeFooX)`QNION=8e;ft**g6C>2H(4vuL?I+<-uLmYO z_&FU}kPH@Sk1?e1lbeNPBv%lAl{i5^oW9$5J%QZiyZ`&smhTsf;BzqToA5)KZfsMim_)*sG3 zsb{E`*KHWftv{Bk>KkQu8$1`0K)chw{RnmNX3Wfweh@7D_ZE}5--lGD_`Wr266#>y z!UR^dW~*myzS`b@I@eHD8at(}Tc^cc!ir%-zf=brDiU75@77B?IPRLu*+j~gb(~fu zai80^^6d1bGtejJL}Ve7RPE{{$m#PZcXyO%K3CsJ%$1BDgZdVeHqlfMvXjw$10aR6 z-5>&2{2!4i*jVx8Aiv@FNJ%dkC{;XE_j3Xn!P{tkCo6eq*Vvrb^Jm9^s6{c{xFsO; z6?{06Ix}t7Pp>%7Ezzm9FEVh3Q&r3_nMliS!T+!>SzC$M7+LYWVUHEYIdv zjq9~D@(O#5_i_b)W4k^P>cT9j7tcO7P~8tB7Xx+CSG;3)>Fr&ip7YtSu6)0Ss<-36 zsGItVtK0DU_?L>!y6{yrv}4I`sv)G)70r>;`HA{*4mGeiRC`fRz*?VM{L^gBTnym%Zqn;JudCalplTayl4kx3FEk$jjYu zul8Q8$=hu%QVdagVSA|<(xq=uPKTBrLga6!_2+3mbL)p=&3Eg?3+lwKh1v2H-ku)O zaw{f#1|0qr4E0eG-aGS;U7(0XLa`KdyH3zG;$CFg#(RAtFty=*`4!lHS%6g5M8*EO1t^ zMW$`X+hF9ot>pFQD3D#`$Y23BZvgg~tAg5O7L8_x&+r4DOLIV{~TN!V0{Uo4W^j1?Y6D?17P|`M4|w8ohM(|sAH^gPVW$ItFkCbSHO8y z1Js*?1J8j-3Ytc}N5t<5IsldnuZ!IigTu!a!W*@+fKLh>AE-k}UGwK1wBjh`4N_oy zd8FOU&x{9Yt)N#MRirgk-1f;9CH?hgE47rucF+@O{JIx?RXku!0k;Jgag2y2rg?(w z4H3NoaI0k477(-VB^BYAZu<>d>DZ+>GCkM>)^UXe_fv-bXX~dm(zw8xo5}PEPBWO? z4-#<2Khfc3ro86l9cMW^sb`6^uyBMThA8Hy)!)zz{K0xTHsqASJ_^lrhdbB*R3c^m zwyOlWLNvAn%U-*4y46U=J7iM}efh0?lxwj08il)y#kjLi#dBFBxy4MBNiN(f!Z4TE_oth}?PW86YEj@fz8^j*Ys$K$m7&Y1}JyhY?m}UssBei_n=hem|bZPf*WO-qZ%# z-hD}zwa&>YF=(=2|A&RQ@3Oe}K6v)JpXhg?{KIq_?B)(2D+EDQq(Z_E3z34r(5Jp6 z=Md=oFqZqneDlVDb^#cFX znCf)ky6R5HwMqsQfRX)g<3tZ1y`s>IWXz29b)XlGkS&QM51u*wDSOE=^T6(t*Vw5m zmlU7*Z`Ta6cS-_(xHPhv*o8h;M@<8Ym5%4m!@6&F?>!ZfVJNSJcZu}Jo!f?CyGO$z^IXFrqUhTza^#zwKJiR zzZ=MLV$=$1f&JVXFwLF~AjQ>IsonaP+_Fj&Gg^M9s>f$g{-pf)5&psLNt-q^`TC=P z{dJ&jtZ42Taa@#Tf9J{0s!h7yuvl11*?3FG9ur~*lHj?XhJu)!xPrcU$T)90Nnj*z z3U_IUK#%a?geP)UGTZI%Ba4p%`0oe@n)p_%XYNrzV&F_zf&4sL)!YVrPv|o;r9zzG z1$cCpI~~XyOvXV=BR(G4{Ex_MB;?Vc?r@h|2H#u+lG5*X6A5~Yckr`i#V5Ng!yS6Q zEw6jFsDt9T%|ctdckF6sw(0d1+eShk(fniISL*To?j>1!3ykF4cN}8blz@hudihcw zLD&S2jRn|W7KQ&brdl}t=|$}W@ntl#>uxm%+D1^+mrL;8HwkNbQCgnA%^_ir81Bxc z=Kl;{XM#MvZfSa8XqTu1q5wD#-_dZ1-1hm+f()tmw?#N--BGM&O@n!hM^%Jmy8Z3 z3X=0lUWGE<=KCZjaRl_`@m{tQ@y8v%&e)Ob`B%Ma(rq9&>`8A7W^-Ayvb&!^1Bqcl z7pq)m?z8nF7m)I!sWtu<^q~H5#XEq2P~C;2%%wMS=DCC5af4y7I22$GvA*0m2>dGc zxH}6ccxl}FLR1C@QP?!QQS0}$^Dg9G;O49-kmvP;o5?2fP528gXP)=J4eoBe_vZFe zd6Fb!`D@V1g(q}xR!hDAj}qVM6?AWdWHt+`g2(rN>TV$yARG??ae3<>x3{kAwVxmj z@&1e{*8PsMv#%guPX52D;NmcOYn(lnD)cCj;2A{9Erx%wRsM~5fPeLqH0u5XYeJAt zx{G+XuHs_35qD<2Ms-BuO3KGG5El*vRZBJKkz`azEId*gxxAR*lir(f%Os0?%kJI} zu^C)=hA&0sPbk%eWG>+|mc5RrB={PB8@fF>Y@s+#0M!`^mAgJNjdf+v3+T<5_czcw zx?i9kCv=eh{V8iqgMY!F#^Ac$zUS5s#ayXtU%wL~V8~NI!QJ9;z!VCivj3Vispj?9 zr9+`6=6J$q6WaK!jXZ^FN8BfT6x{4Wgc?tOy>g*;!;AAd6*;BAvThO*gi+PIK;G*Y zkWR2EKqVHhk7k@&$CQ8+@Z5}7Ae<%@feAFp7JDC=btE`Onkc+yN0GJVFTh?1q_FM8 z(AZGK{B649b5pjoyB<0~6T&;m_#T~{6v&j-5(+HJKg^< zYeXLktxYj6R0k57Mb^H@kQe`kKbtD)FLCa9!pcdhY07d&ySgU4M#MxTgZ)Q@J?dfJ zE#k7d#3?Ky3!%AJF}?RY^1uo~g%e*Ouf;GjS;YBGtI+bf8_Ccd>}NXdw8$6Z?mmYf zUqtP=tK3O$wdyuHI2!XYZh18$R2Lj+^s6&-GwgPTY>gbtJw5JKsr7xnYuwd>SWaLG z5B-jS)?&4Oa27=8qjd4(_%HU|ec})P*NyTDk7VC3c*%zl6y0)dc&8TJGN=WiN3tnL z-)bw->Y#n4Aqy1@gQpv%k}>Vvr>PCtFwg=So$*XmnA(P4-dzqVGtKYB5Tm#kbA(vB zAT!bZ!5c$(k8z=C{lJ7ocyL{r z_q*Gzuxm17)U9?qMcpH%I>+w*V(6M*PSP9EVoUmB7nXaJJ29rJ-=l9mM!}gB!VOGjyWK$O zR97%Cf~tZH6Iy%%`wITvzOVz>q=D$Vv?ftiVV*nEBFYryC4^{7-H1fP@-hkoKEIfV z9Dl--Nujb>qwG8E7-V&DS>gT+IYz99N`kx^%lPb7vz;Aam-QCS@#{dzy>MA7Tr$Tr zKkV}stFnPT|IF2feTb?0R2S7Qo=-`7=z|g8oHFOn205Tn4WpKEFC$yP6?3aR|0!aJ zBdexCZMx|sI8@{ne`(0VyomzN#aq;X;ZH3gic#bB(_fBO<4MK$8jdoC^_*B+(B6xj zT(lw#<+kr@?YUUn2U*PS_7w@Y2Q-5OURB6Uq$v0!++IgK@HWwCx~O?N1O|*dyvm7{|NSn z&s{}<$4#+Yotkg6)loDjwHJ<(cja`Kj!ulo1r|6VN8)`gPyP?a27}kfm^{K!(SPBJ4=#|MG0_YT7! zZ@$u0L$6FTN1$r+8fNja19@tnJhf9vAD%=p^9A?Z>K1iL(7^lrr#1kEXFS{tcf%$; zH4;aiUS+63PB?pFw*`?{bt z{Ywz193ZYraWZ%%a3G~ezFbm%b0&ouPrFzi)~(9A_HE0PCP7u*_hsXt78 ztKz_z*J-`A>Qx{P(3nu58?!Myhr{Y9gYFnL2OhPT-0W}og~m=dv>{E?L|IXKA;~%c zXYP>(kgu+n9qh33vz-(9@aCO$qH{Br{;3IXunKGj+zJr;M|2A-xeJ``D0#YBD`9wa zd(Xz>TsW}(#y4ZJvFg zHsjw98h32ooZ05{PwuAQPF@KJuD>5caYxE(o0K4_@DcTENYPZ*l_vaJZ4+@R$p9zk zx@EZdiz4#ThySUQwGR?rk!in?4y1RkSH|Q;2VM+OlK(N&%TZxYCfgIX*V^Ypd}`pa z67#W1XLe7YrwH@^P5sdSEK*ogplRKS!T-ni=yaA~!a>;ulp`D-1md9D}MzV%aR}?my+pPV6nWYQDo#D}? z)MAW^Wmyf7BGt)e%RyG~W3r%`QbX}mlQ9G3WSiLcUCKkgDecj#1%1lM>vpzpseft# z3wwAla!j}`DsFhdICPQ#e6=8pVHtR@tn1+$<`MWCot5|4G=Sdu|J{+ z%mlOkpQ7Ohhj1tXl5`zwuw1_hF4-<9O>Nu@c~nI=@i6sL<)PeOHH~^BO^In$E_?HP za32T%L+a;>Ppa;6yP~&sHvLY-um2GZcl#7AN#*Yxnf54DMmorns(iBl;KjIJp-$zw zUUmttRV>&oNQ1DU1Nkan@AgzNnn)Fw`wLKhr3xJ1r8?OUs3(8LCKv|GM=NGbB;Ed=1gvo$j=#++ zz4bGiyKE0(8G+WSO(I{No{CBTZORek_KHj<=)=S3@eu|8=}-+k#qNAxO@iKVWPf;@ zk|_79Bbxk;Fh%#oQx95!g)BIRxfzh z;q^n=ijkU`E$E_lci<~uP$T>`<_Rz_tQw&JpsZR`ymthA8)`5QO<8&#fAsC`Y99bH zIF*-MKgLXdlbEI?Z`~>OF*w>)x~;xT<$!|dechtnK-6miqz6fHJ68(VRpnKhvxXF# z-y93)#NghgT(Qp-__G?=r2Vx7lk{9#Fp#GA)T-0u=}ykh=H3b)jTt_b1Nrl0t@hvw zC4t7{N#UPQ#=d$|qGI;}C?VWSuqv$FCZ^FO>=u@wJW ztIv%d+;sMavpX~8Q{?8JWcD-s{Zc3D?xk5|%EJ;7u;BfT3Y!<(=tG8bGm~2gu=sYD z8w)q|?KzLG#UCMt`mW}m%+ zHXvxmYz1?c?Pj0dFH*a^q^3SNYIy4w%ccF}kAqoxL;5k7m zPDI!Zbn;(ii~E8MvliuCem0=~&(sR#VPP4Q6G=^%uKYskbd(9*G6_F33w;I3JX7<} zA0gtzr9}AuhpVS9lzh5>>@fX>{}tu)Azv;tX2FJUu&2G;v|1_Ez0LdWf;muo)z}A= z^@p)_VoToMi%Fx8&N+h5GhZ(qvG+-2bKE)``+I&n??!U{z_HM%nnc-(@G|g>PVYO7lU~~sYpZ@pvPc&laA=S+~vzJ=r zuFd*|ck`{d%{Zu5_V^S{T)dacP7;ph{AC9S>9nviQ zBict`T5v-b`KdbRwa5)@2uREwP`eHpIJ;>n^dt8QlgR4(wNS2FW#TgHHZ(F9XS6|N zSfSAjRCbSj*199{M#KXlGoEn7Je%Y141K2L)#uuVXUmVveN6ITuE8}$9QHI=;8~lC z{dW;jhx20%PY@v%?s7YGT!~{$SLK@#Nc*0yvr6|lPj9X3E${toPIluTp6dnc-qzwrMfV;+o^d#I1yRdN-T0-nU&=nG_yf}IzE%ZJ;u(P{da0!<@c2c{ z-CldzgYOfbxf=b?d6ThS1)vG=OITTJ>?Y0MmgLh~o@*Ep#Frkjbob-QiBUI%b(P29 z0kh(OoVDVtlD6(g`HVl!2LxrJh+bB={5h-Fy5Zlk|4lVdpx-n2FE9?^Zg>jQlBWI<)gi(@B2O1HAG&nh`NY%xQPSDvA)2#5 zVU;g{MP~A-$8L;rJ@L49R>Wf3X9AimfHdeXkZ|U6e@~dU2ut9}y+mMx;61ns;!CC-Ja$a>IDIY|>oJr0482bMc=a3|B}@ z@Xc1(uF!;MyudkuO69O0(&NDjYXKW~(PRd7ci4deqd&jA z51sc_(_FrgHw&2!mI)9A%qry}W3$5ra6(`^ct!U^JYk5IdwzpRgY$GU@_M7UIb_X5 z>Lo@4NOG>i`4xMAtNIvzd|L-ueQMOuBYZB*AJ4ITss{S9?CHNMLjQHGD;>kMZ`chu z4NO$%MF=VtnON(Jm6E6ion5)l8Pt8`P?&7yk$vRQka#CS70j*vD@C)!)I9_3W0WU* zNnzAsH2uF~;k~FhduT^|`+WzSsV#scJHXd}IP$?iB5uv(Coe~md9?J|sTmhAzMs5H zU%q=G%p1wVW3;q$`+F>O#7F^<4TB zHh&v?yZG5H@EZbNRdeI6+h#t#6dKs5Jp-y2^$&m}X0%K%s&acQ3`=r9g2l?(Qzd3B{pEaM$AQPH?y2 zF2&u0BuH=Wr}y~{J3Bjj=13}XWvHC)`&l7PoPZb86~9yH3+Nw$WWY>#3A`*s$%L*e z7yTHaPKOnMid<+T+7lpWeV7-M~SEMjp5U;VM8LwVqdq-03~Ad>XRN{L?|F_Q<(yF78r{67FW^g1OYA)^t0 zU`GKQW{_{Cer$U!n=b!*YZ83*3&-1I2}KHB4P0+UKwA=o^*UvLBBgyihvZ7BcGHBh z>x^rWNiEpb$^MRn(1k`?QeUTS^ZN^OD6@3m+t)Q&I{r9OY$NgO(EGe{b?_8$&pPkT zBY12yt!I?}?77eS>2X(>QWen-!uybT7ck@EWLU6a-}GT9i*OgLRabtH%u;k{Z||p@ z%>nlgVH$wD<4PB`Z@mmx|G2@seBLL_;vM2GI;THMpSCuOIw7Knp2n^I8!SyMncrP` zo;qdIHt93y5q#J!I^HEU@;oOKD1UqJ#W&Q{w8;k_N*yX#Zx)DWUN_vJ`_I4bFygw4 zwk{s-1*f3&M@tuq7*NYssZIx2ChUrL#M`kBr02_F+L3ORbn+dW`&L@?Vb2=dDdVj| z0n4e<0`tMycj{s9az_ItS2sm$HeTG@VnL}fXI3uLg2r5Vr<$dO!==}J&6uAot)7)_uVI~WkbQXPCZ(>_}(n~8}4U3@^Vkh8ZBC>c(W9QQS|7QULrafd8S59v9i>6 z+f*Ga=8xvfg;%=X{NjIv=ulZksK%W}964#x#bWnTSE=7&Snw0hv~8m{->RT{mIDF- z2`7!?{}4(YDO^a1`;F2zbz4$)qS^q{fK^|m4dc6(Qb($9hqwoXZ$gY?4J(sa1iaxKCR0;~?6v!6z@?Z-ad|9xYUh!bl@>?zXjY>8N*Jt!5 zSIhL~qa9ZtG-Bh<02;qbfa^^dzWCG)ti5)#i5VLV`98H}^bEPW4}k4IHR!*pi{^ry zo)lkU!ZVK@J5KXX8#SB(OC6lM?~B? z?N+oh>3W?Kzw@|V-;6US;HSbltOco&8^0%(+rtF5uaGSn7>hmOX55|Sc)!O-8R?8} z;Q%^6v?$E_c_C<^@Nw=O(3`B_aQYpu+8<3~e(N^tr51(-ewamwQ6k5nB{JXz3h$4?H{eWEai}$Z*1-a>FxT9{qY|Ci zAdZ>6b&HGn_en*AL$j_?mY?WuB~cBX^beV4bdt^X^Hf7Jczfa`4HJ$KPKe7q1lBx1 zK8#>aWJZWKhu3$FCSP~?xH4gs{jW^# zB1vk?^vC=l7cL8pRE&8aOWj0Zhx{=y*vKtzB13fPZN5wrd(&u?e2>@w?9;6adBbZ6 z;FrC)y^q6eNr;!#&FSD!Rc{%L^(gh!>FD+R4-9n{*1`W+V(CX5ZIVQYWs|oO73uXb z)^o1M^ADlPXLs3`-_yY}D!PZ@RrkX}X#3wc(WIa?>ILyJR>ta`50qXVGF7uDSLo}N zb*C`~EUKlCq1M_Td`EI5Z^N{3Dn0?>o{Vv0F^W&jyc0T}C-e~2OYrAc_a`uH=cWC* z@>R04J*CZ# z#(GV|)|dcEJSNes)!_VhnF=|5ZI{oDa?cR^8kqO=LDYr}vR?_jhDY`N#{ee$zvV+I$K?j^Up ze(H6A`f;TMa2>)!vr^7!^y7csfxaeYvL?3jT+oJ3a+_l zYaAD?5;iE&c3dSSIVkwp`Ym4}iz88!yLijuE!x$7b&sfUsU9z>_bNBVmuaz;EX`i4 z2CZ8dGG4GO*adFf>z&K->!Wq1@bq`pmU2j&7Uu>mU@4~)(tVVB*>aYeAsSDmqsUy%*~(netPPBBKx!^muu%&bfhB{Yko?Ry4Qx zzlEG0)^hWoJQxqot}-E=C%75AbgFt9CFgdcg$OJD2IZW|d%m70yeBP3B6Yw=qg$(6 zj4}R}Q9=-919tC1TGN)jN(JJ9LhM)6VG;JXzVAz{umSJl7N%8cR?b|?e`T-Sb8Hu% zrLJ1V!>yd3lhX&uI26Rzm01*flVj0_pv%UgB=k4)N+AOUYG* zMR`Jusz9_(C3ENatVuAi8`2EiTh?+l_{L?;f9I!M_E)GI)Cirb^L+<%`sxPGMC)`C zN+9AgM?;7y;q;X9YEETDr`>)-J5mR84bKfGtNd&E>yc0Q?R)4ygd5Kb`unD*&>iyq z;p@(v2Wsj!HJ6%K$wLY{$_?6Ym!lhq;ifFU{q;!1qz52*=1QaQb3W57y{_e-Pd7Rv z^?n9*$9SENJT~iP&6KW8>dQI^%Ef<uOz0I0O-ZIM1;AY4rf9Sfcepi>;@!C9D>R24CR+ zHuq}Tm2?o9jmPb-J;aH`8fAKp7Z795)v+~yAai6)cqB(UE8|cLFcB-8;6>rr zdQRN*{XYb~CoM5Tj(-S#P=lzi$cEW!g;wd+PBO+y-?v4nH9d`#?NA%Lm0(-bM8dye z&R@`45Eu0O;?^IxVGU~^lZEVlKhnvO(UWx>dF;CS6huK;!QNgb$t3XqeuI`!|K14* z9&JWUbN1jX!F{Y3P{PDlb9k98=4cq0c>v~gAa4(te>jOHeoTdyPBmDU&qvv;s@CNZ zeATz0su>_zBH#6c{45a3PXtZoseC-s)e9sM8ZwGQpK0P~T7>xX9(>%j|KN4f#LIq* zk#oBOvvFQ1;RQ-qOBby=(9x50&2+Lu*|+5uw~D<_`|pe_UkhO;xULQNH9=+pJX^8` z<>|&yl~SE)*LGtfJ`n3%*V5hMZsp>0@^%2Td85K=3*F&Q^)X-b*H9D|G^8c$y003$ zu&{7G1ypFIYJX-6G1yIDSPET~jh$Hilr&*gvn2fSa#UMbAp;A~NR@I5zz7@)CT#n7 z%{_d;{|V=%A4t0#UznPW;OQ#ph~sLYs+}kj(0gqnnR%VF{~use9z+>QLik8uoJl?x z2H@^Tw)}`*lA!OBd&b$$5(oI` zQ>9d>&iDoq?K56Qyf^g#fz}427{Aln3;)rEui6S1+Rr*3f3jhNsgqneSK44rS5=g< z*uh7@Ulrz`PgRW`0XbG|*G!&*B|DqmVC55LZ+a#;MrlqulzRkf1~|lp&I{*vv`F9N zrj}>7I8&;JUMMeb zY>i`TMdB~bUAUY%$#qJ_B5)Mv!ec*pCKsG=B{He1jf)#-*^;n!wSUn1GB1;Mnc+vf zUFmBB+3Y^pnhaofG^!%6-V7Y6GZ*g&pK*MRZJWFP?aO|$pv6qvqxSc7v-EE2+%Gg3 zT0@R*$2M@|=2?$hj!BKTVlD7T-oy#NOMy>;{n{wD_en|-#c z3uS|d%b5HQB&P~N1b$Y8iTwYK^kQjtryTh-t-E9**jouw**PD$ReXLx-tUGB-Ac%xpms?Yw= z?VS@0%RSqU{mSpIgEcm8hK%_(YoNu3gIwg-0PomHktZ8CbzDG5|FEXp@C9r*tPK&l zQ@-W4Qd-cISLri6vl2Z#xCH-=>xkJ3TxuW!9WuZ>s-a zrXFaO`zKztLOdRq%z--J^;mM&Fq?701tB5(&SWl?CshSdml#KcL~H$gInKO&`jHhY zOMvq%iTV>S6A2yZIDUW*$?k7tgBPq{7CXZNJ;a9%0pA{U7MU|{Z3mx)p*q_K0g?fZ zpa;h?nB7)RGSOR-QE}VdtYn2L+d4|C)-Ke;btaUG?xRT^Ud6_1!r{Y=buL#87-pLb zqu8t5FVZzYxO;7`;D%2*!|-3pS_8vBhg4SY;h-L{)}(12h*3OVul?@(AB!2T4eP6# z7WpJ1ZohkA5ga|J$6T$+v+u3U_}S=>J9#+U{I!A8GOhtGMG0N@TN0#gu%{{K#xkiu z99zHSF=e;IjTlt^9Czv0aNq0GE?2xO;#bn~;~IQelV}suCa_g)KpH4=?NLwCaYojA z2MDykb~@M!>RgF3ZVZ?7PKB2}{Sz`Q#fhEpllhlwOWS5jVfFW%~<@3mOe zK&asv20-wxu~<{gnFm9cZk=v{?}Ioh_m(A~0#aPk`Zm>6Xl`BP=PS26;VkafHb#hY zwJ)UW5CM#>X!#7@Os3i%0;+W_bNBQ}zL1drEkEU}*g|@7ZBndj_=#Ff>SN0B83#t< zjBt?BKX4N*m^^;W)LLDh0*qcLI~U2}@(oZbc#`i9!AcXj1dtPu{Q`s7%szjziEp;) zV~llkx}XagQvA9%M^w`Q8f;oYmu%86>tcAWyD@BoMZ%hn(pFPJ!iu&b*3sN?22tN!O3tYLo2g3MmNjjHMug5v>t6$wHkezGNOQxR$ z*cW1%F0{d__oFQ?kBL-Y@HH1}v>2mLKuQji(ME)ntv1_kBX~hQC)4kA&fgBtS19S) z1M4%$k+#Q^dv-NM1)&9Gqio%RCP`Nac6oXFJn!#z4y&DX8O?!CWI?367!zQ`9q*Ly z*=^oaehsR3-RDNfT~VQnKR3SG8}k?Q9}20PTOutnnj)X%1TJ-{%j^Ek{OHR!<(ARJ z_L;Rv)3 zbgF%Q$T9$GjunG4w>|Wyn=T)1)H4^pzwAiKuMiV;REIb?_dT&Gv3X!(#jN9PmD(a; zY%6-P*#0$oDuAtb7ajZjozRfMqN-bs|6We8aS`o4FJB6J(o<2m$}{>vl7M13a~6 zGW5iHWggOtnt54jdVm-6W-2RdfGQ#Aqp~R46E^O|Vo*=Qx1-%v|No&u38&f-S4V@R zQaA!Ct&4~hy0tGP9B(Q_%?N&`7yv`pL-h*|fbGXzv?kTN4clZ}-Q5?mvb?-N_-;_h5*q z0pt8`iUf@jr%k=GxLxDuKzXYnvH3Mct z$N8%XO@bF_b_S(sqcmGCVq<84F8H^_e0j^*f#?Cb@B)A$f5KMJGMfw8vHkPwRwv;I z+hu0X!iG$9zx!aP;{FX;#|!@*-zBp*#>7wAR16K+p{p;5-kLdU`h!7*i04R^z;^ki z=NhwRmXS0cg8!~AXU=}p4t=zey(c|$2!a}85Ylc}z-=*d%z@6n_n)Q7Tf=m@5m!fl zx6|^=3}^Js?EJ^4VXrik6*4F7i4)ohpC<^tYwLO=zbe?aJ)3?E;7T}Xna~TRT)W3_ z1F527jFe^{wmK5N-!&O3*|4|pvl?|dTe90PIAW;&UiKsOf#l1ml|@vL40xGM-&%q< zyIai5|2GTccJ5nf584gT|A0$t`Y5`Iy41Na{)FwA_H~ewLR;tih)e`J&hvBnSFI7S z(C`Y$a14=t8i~wfm*nrWO*8Jh|DL=n4q3JMz}^=XRR5DnA^A`hnQV--nNt#L6%_7) zrJ}J4H+QQ7j)9N%&S`2Bqv7)xtr4SI)Sm0wZazFxh`)tY8{UivuGmIX^`5bW;#E2c zyoMjMdiYrH1-Jq(Ui0_2rfP0Eq3qT##xL!6gL>}>TYT2s=#G6YZgylWu_6>UAu7-f zUS{~@x|bX8?(`$)_LbW0uBFU93bX{6`Fdj5A>uzG_N&je9y%tD^ zJ}#xz2~2w_@{mvF_#lL9gsn9>yn!=TVf)=b+7QQ2QjNr%9v)sn8gMCRDhHD95NuN- z*1t8llJ^ui?IcUb!|cUEo0{DH3})2ytq2|`s@z9t$_5|M=h}%>Eq`qVVHWk&o>cLX ztno+Sel^zSzs&7S+}8&*<*FiKwb*pf?qv&c3Z|A9F0y6)@yzl|-tYXw@D-#~5P_85 z^fb5fP>=!6mkA-I>qDi@#|w`0zDcy4u~eZv^4%)roum=L+Wm*XD{4Y(1TH6M!eeko znMl?vn5h9oLRJ(wIbzKGyj;w}q%(9fstmN5I0-`s)--Mg*|Nt_n0JA1pna9UwYv~L zUT>!3T&;fE#t2@a#%9M`%cL{geLMDLmu-76_87Imjdm+WnEiX;Rridk`4A`-Q>3Q`%nH4SD-jLTp5dqTb36WmVg zfbs}fI1G33l+4K<)0}NQAds3FAP_(&H0KP_u5<^0 zkKX%wVrctROyieoz%AaTuH7|s3nd=bR`T7i=pp0QL=w_FdpXv_9QG`kQ$ePIhvjdb z=Zo){g*;@H+fLiRjrAM%z~= zgN|?s0EDwp{8wKp9Pe0uDTDe=8##_K!Fe{G39PpT&$DNlE+tyTmT+4&@=;N~Z)-z#XD0H%-RTAcIW#64$0wzt<{wOAzWQ)m z;5qB^kMIzgD!U%uVbfRw6cfOsEK=cgc0w}Sv04Vtk>qVGykrvbe_Bri{sRHix&)i$ zh_IvTo+woRZ5gNGXBFw%Rh4nsVijD`r2LI${Ci<>2|b!%p;(Zv>`WdXXf(n|i5npAqZhMPqZZLw@Hrsn@$lLA9|El? zFoXWA<<#-)cmEU+X4oJbOlLLnMf-`=YO0I-nmo4iC4O+j-=q{Nsu8xfMpnHb zt%WpMN0P!*p>BCxq8p~h_(A@Wz+_TT!b)V^ngIWI=gj@9W3VivMe$#E!RkzwERmNY zZPR&<_3i^u`K>av5f*M480CFR{LZQ}aX`De0rv4M|IQG^fA(?lsrekncD5MJ!G>Pj zbfeLAHsmBF+;CEN^iA$Te55S=&Oi>_qcYu=q(3~?-71fmDJ7o-0!l^3=xv&wViaWldeFoGupRW>6(Pmo|Loxdj9xh`L5(k;|%q3 zGJD=Mns!#z(w;4m>>Nxf*R59w7h16|pzO%Wezg8_6dVVLe?mlJx=|QN`?am$pCj^< zx0GG)G?Y#mY5tIEFiy26j{YTN6m6>Q=G|-YPukvE%l|wD@YpZtm+Yya0h|3DO+L3M zO1``M!%oj%{>pf4dyoAnQwLaWD-9zC3th=sR5TYN0+w6c5lI3Yf5v(u zwgH53Ty^Nn>6%e|BSMlagFMVzs?7#JL8mi-xfjdVpnnJf{}8m(pIKj7x`E_F-D0mh zfB~3K6L9^-_eg$#tqJqsV%V0iTKTFFt@aU! zHh)veA)hgVlwldG@9afg(WH9sz_E$X1oo+fUJgGt5@~Q&$xD?&A7~th&FfbqmdbNw zHE-m;uUXYcavrf7!0-UV`?*XO989W0;4tL}<+`ZB84$zqhT)>-lLO$r%E>&@z$w3B z*QmrFMOKcV5q~F!zv6n%p4VJWw>POMWRiyAIR)lE4PnWfvZC2h0H(p_s%MFiOII_4g8f4|sdU9{WS4>LF` z`B0L5Amnn_&MbxXwIx?*A#fjQKdW-Srv+lBi_#}gJDLR|CZ9}OR)uXm%5y9)7`LOAVjRy`EeTTdTM z+-r^W!-VU31V8&&Wpo}!AM!iWCLBP%zSlA!DRQQX3HO?>3eDSFt}}Sj7!_7#YDuwS(Ul>uJH=k#FDho?j#PlqK z7le2}u=9)=BB(CuF-y=DYrmKITa>mdCNAkb7;9iBT4MBqQ4TD}saJi@+!p1Z^>&sS zQS=mwG9}Ida}tNnfg$~(WX^s8RU(ohBk?6N*!X);EYwl%E5Q(xK_9LkVVNXz_M`En z;f5B)e_H?Z3uMNX^uEAfqUfW`BXiEIL+x{&FOMGC4>K2Ch-eJVuW-gpZND7in4yDJ;uOoE?YD*G}nP;H@i9ox%%)L>}1M1C49~=$Yc)fV23;M2B*}m znVMsA*z9YV@P15y=vE)bRn#ML-D@pi6E>1-*bbph`Y4u@n6FT1Hm+9p!`Vo{Qs@2~ z+!KfhnuAwSrmJ*JoSSz??Lq8+`Hc~-!?W|| z{z)tSSvkZe)1a%GT6t{|Ekx^#7nHjo5{KH(CMoEYWOw zRw;I#F;G#mpSAi@{}mM=pclr!*qR2aCB5Heogl~FOC`2GQ5mnALHuPBM?o<`&!L}p zr{c1EP1EL-|Et$IG6?vwY}R2jVvA{EMEQr`Abg>VPz-X=2H2^lVJ?}rvPk)qp=`o zROI&iA3IV>T2Ye^5;Q{s-{jGR@ z3dr=qKkhz1?5Mc|$xpYxl7Ju)sU$D7Y(;c>GwSd_PPKG=*-@l$hZd*j>-Zf znb)vh)B3%Wflmf%ROdITW$r_UCIL;+@cHv*+b%^t_?novK~7a0(o)UCALiJCkDwJ6 z`;K;}UVy=&6(l>=zwB6q91fGSn%W@MiL`J3Hdy=DlQk(<0D8+&FkRnC&Vb^vB7D4h z_r#3v@t_%X01q>|TK z9E{)OI=`0qhAjj>?!x~oBY>Y+wr!GA*5uqT&T(>HzqYqW7&uGg@_X>;gl2Cjkc0Np z6W2r7kXxp6VrI$l-V5FagbO)^&Ko2N39Vpy?Ix|bVj&M5g^$pG9Ilyimux|-*YzAG ziJ)RYmGY2X+^K!e1>Gzesa5+&BBjhPEeX{P2k8Hg5Z1`P#Ubj})1i)EdHlq=bz@QZXYU$H4b)h6gcl1Rqt~bk|yxJp!qVk4CL; zy;eH#OE{t#E*r#SpZ!e+bfaSh0POT(g#I?v{p}&d+-s6KJn*DAzDcSEenpT@?lpKaAjzmgUz21HH z)QsVP4S9=`Q_;NtlJLIbaai^5ayc^ zK0obeeBmQ$>_3q2=2$StiS^bkJ-J8q8w*+S{azT)NjeF;1VJ4)ekM zmP*~@vr%G}6%fQdkdxO36AwUq`fm};L1;MqzdLf0#`$0V7UD_wu&d{Dl*Tfh^iXHx zTszCeD#Rmw7m>~?^lXDsH_qhpZXwOtJDgIBvdx0-O=e|A^ld$HSwsqRg-~nHYEvh7 z7c8}Bbr+EM!g7xk0*ZQh7htuujB#!$|9l@n1UFW=S%E^kUZbCQ)=GT}7M~2d4hwX~ z?k`*p&NLGcxLFwopWF62?Jx4{NSv$t%XI9CQ44vr1cU)y+M|45b5%`yO-|?+kD(S6 zn+-*|%zlTQgSXo&sc}NcheZ3XAH(gJN9K(W*s}#IkPsazV;cEPtxv00Z7hn1-IUjy()ZqG+NB81O2O)pH2>wG{zVFWOIc{&ePMGyJ+;Wx$%dYS3 zEL;{F9#}JXQ`y3scj$G`iuh2gpPvX}nI)de34lnSYHmZvA2Fae@~*Ys@6pJ)K*NTR zu8n*fm{>ch)ihwGarRjaC?Au2@Jz@^r69L2tqPAEt$hQ{oJ`u4K2ARkr#kdr3_Lax zyG=gWmODzhZY##u&$P}$tazL6n3m!<;Ir>Y(zi4zFWZtye=B;kbeI}*-I_9TWlys+ zWGlZL5=-8Hty@nJ#=Qcr9miDTIN$~wnTb23qIGV8qrd+smT^m){?o=A*!>?g%RCxYL|Xl8uz?6tNGI z(lZ<$*ExV6x7kJbu^xU-=V6jeo6-bP^Ll16>c&gdpE>8~x(daLj04`d;T(mZuIx|g ziy@K0guv`Nmdm1J=~uan)L<{*C=>xNaJY84>qFo~Urls1YBmoNvOy?LY|e3aqDY`0 zczMn;7G-U~vZj)AX=tY`_Sux$KrZLZ`o_E;D5CJ@MR?vTw(x&vFK>84f~Ynq1;p*M zC_#ru4$UO~=J@&&y?;VHI^UOnX6sRLKk8i9$GE0s~|KW4HJ_R<~-; zeXmsBZ-|w<*Tt+?eGCe{qGftNhq7pHlW}*tZ(5*)BR9tR^JWDtw{~ydh*EuELH%g*XkcN&td}(mzx|_#ToX8y6yWofI4|rXVT0^vsQHyK? zQgXw|5dILt3!5|qjaeH;zI*^#%V%)m<=eCPAs1BV1$zpnUT)v;Nfg1*VW z-~Guukppu;X(gG*EPh9Nf75Irip+16q>hYnPMdT+MK_y;@e|8R^mFyPfAJ=)H45YO z8NM-H6aX;MQpeKz+3HPjEs_5B>}AMwC7u4zrO`e2e`8Dlv@nlgn+1{fBS-KH@XaQM z@aXali?m^bX2b`m#S-a2BxPyIfAA%Cj+J%y)$_5wzaPiO(|=U--0GcB$RsSQ&x~HP zj!smVex%#p5`T^Iaf*JJC2tCtWxXsZ@e6+Rg{yEn{*rWU9AkJrF-|vcC$MImR~q28 zkSOYjqG=4(VNSE>f}JSTAqG6VN8lNZ1;s7aTO&R0tXb;gub+w>~)R2KT z-ahp*y*@pZN*^J+3%rzW0?r!s496!I;TWDOoQf+5B^5BMjE?#e?xN#AH9A4Uy;W;U z^S`Sv2lKN3ccF5^Q+?#h;Q8%8)|{BMO{Jfrrc%6{Q9 z>q2J<1`$D~PKqJ#WEyaa#hxf2zb9mW)da zq`Lq?fL1`Rj!-ak9J&vm)mKBn+JN6rqVAbl$nD3TZmzGvL$0aytmk1#&f{Atwu*-91B(vN)H1xJm}GmSrornRe;_XIzmjlhN; zx0jjEphF>T6Y%$ox;l~_IQ-Dz!4RapS=|au`J#&wH_5!E{6y|aOSaVEgDRd$F*&53 zP_);Jf$}Y=&W7+Ple@qD4DL~k5+D;|J7d{MK&psb|!I5h}pRo0Bv4>eE^D;&7)}B9+M<<%*;a5c?g}!h)TYhxM4> zA;RXd(x001QeS#It@9_CRW9do1e?Tye@T?==hCaoS}vb|ob!+WO@FjyxFjO_G_sol z7mO@im}M+vA1R{2b$joeJKlz9wr4>ek&H=dZ!j_``TpwI?dBrg*?TFt>_@YNyc1GT z@KzEBsJ<&G(%99hWFjw{tBki8NBgwk?5ADYDKx1xa|)by^080;qt{aAuUatQnGQ98 z&ZS^M=u3soPIF~9OL2FJq!O()o}JzdbDq$-q#k(R%O|LF)tJ3zy~gvspLhFl>CM1MUq0Mk1Sj@ie;d;lYh~fzInrEI< z{ug^gdoF!yHs>^F$(n@v^--YO6Ht~h&qs7=?Ywekd!ZcH;a0LOh=zt5uM9U&nlWLX?0@rBos3Qs zmEdP`LGJ?ONe1q}@ta37C{=5I85-CD^}OTkT0a(?gv~rZmftGe^3W_z z$y>JvjydXR^LwP`zF!fQe1X>dg(tRT63{06HMUUUN7C2)Dzw3>W|w^YM0Z=T=Hz+b z`S3Sja*NXPMjl9}{)}0>mSSkGvOAk(R#!mHzqDxCc0+MYTiEhGhpKBQnR!{&BHw=^ zw$Ev=%?Qvax;H-`nPBLWUkm8IOKFAuuLH<3LT>8PVKWR@241Wje~{_9LXQ4FBLn*# zT9vaSMLN$rreRBW-opnLm7_WHJM=GYPH2%rA@_En4)Mcn%z0y0qo`#`=}znaDJU@zsPf4!@ZsTpm+<85z5zUa>|LDt85@!Zh|5bY(v@;*wqW z?>;LK0G7PCRii?!8e_mVSeC<8OJRe_e#;Q+wmajtjAGGT(j`c&_56?n-YgcOKXUoo zCk&DPZ@Sqd&))l42Ve43B6XNOx~%}gui;Oc3sIIofr$*8`q%it=gT-Nb+$kJzNIV% zo|oyx^7zXlqftBEgb!^#pKnt#k*UYiLAhG38t{+A_cIw;AG#XLvV%VR`_h%f&B7Oq zyR{sZ=kuFlw-4K{i6Y)wk=qec=f{w;17vz?ouR zw9yUrf&Xy8WDWQ;dDAXAoTtlN+RluyR-brdt;BF{RHugSw-KiifqakNRb`hGRBQ@1 zAn~}X?%3Yby_Gru88xOsKydY^NTI^x35_Retjy1K3VxZCP|EMi770oiY#pNB$_I80<@qX!qz9KrD)e>ryq|bv9A=ipA;`bum4%1r9$y%^$ z?G6-T+%Gry1GVe+LG^B3j!5NDZ#%_T_gh6NI}-ky8@%rd$)-CrrzT5QFJ81sKhVqC z&XK%sc6}%VQK-GURTPw2It#Y@8#>y4cKr-WKhG@?*=hT*1Ttz;J4JQ`&3sXf=2fqr zYSKC9wKLa$5{w!aZL=i(je5A*BPZy7ZNfKTVMy4ea4-!YFX);sBy z9FrfDx1D>H06_rv>(jTC{q8*sq+L5&qphED~0(MUbQ3i)Aclw;8sG z3UqA=e=HeFt97UQkUkyM7co%AS;&$`HYz(4GUQ>S^;bSgNY8Opg~~&$u#_q-e)>-I z%qY6``^co|9OkYlb#)r>OE`O`0o#(>J~!6Df9|_s@s;WjdW+TpJ4d|vOTfOf4QrjH zJe7)rL986%Zb@dA0T>j6gqam*(v{7OLR~GHAD_eZ5_-zX`f>dmh=^)A&cs>QZB4G)KfTy2Z8cCjbhSSyQg?+!**ufcxm) zL11#`M_%V}WSe6LQpH>;e{sQSt|rb+?x9tv%dD2($AW2*{4Lgq&QY~99vo>U0Rp6E z*2drOZd1&pfJ$VT*3bRmbaza?fY?q2eDyn})MTg?W!vRy`1H;Uc#{t_6I*_;ujSD|^@KW6PqSMAL0Lv3n{D@7wW zD)e-)-oXhz^6t`5{UrsqVh=HTC_qN8p?ajrqj&LOrDZ>Xhr`kdoN=|(w{_B#Blcf6ZMs1`KV%aYWlM;q!XF* zQU_Q4zsX7NsJj#P>(Ht7ogrONhq8TXaY_QebQkd(@0p{hiR*r$mX9UgUcdkMy3;iA z*d^M}?V_Ph935?mZw92j2q2U_^bhzacu*-sRD(>+>5;wR&IZ4>-lb-&ky{NBojTK{ zMxp4G1|?<<#ot~2fpS}5$u-HCjJ#3OR#}}HM^>t!+BYWD_5hEhe2zk?JA+$r!0e>b z{g=4V(s3hSC z)a32+koVKhBeZ6jIMZjQl4BB#FZWgwatLQ&PW0$E5qBQAWtpK*o+b%(VBLC1xUAhT z)%j^#)DKBbx>}|_=q$LgvK;~zUf3bDKf8bUMD0^>x3AN)=ZR<1pUs8ADyJDRnSB%? zoyJWkSB@Wa9T!(>sWF)r472sC)Sdq!h?;sG82u=j=FAx8IcE9Fi0MY|a`| zl~I##InwI~RbGH#1K^2+Jbmu4s?23yMs<=iMKARzS-DspZIA| zR9_;VMqNv!0prq7KI=c%o7s;GmG0+yTV)VAo!zGwZu1<>77SZfxy~izS`w-D{&GpvaId6`W=q21`Nperef~x)%Zbpy9If$}GW%>7|0p@a|Vv6CAAykj| zB(r|Xi|}JgwY$XLx*SUbkar_tQj0<{s_hcNx@-{99AB=pEq-|5~`xv8&k#?P3b;NYq zY}2M6EqY&xCJw);OQqF;P>k|GbO5*rQ)Eo!JztSTW0Dd94Q_|W=~0#D=A9A6EpKFJ z>fu?VVn_&p*6jnupYScxH?MP-qEr+S`dzoxr9s(D&oV}`I8V42!x8|tk|H*+@?_l7 zhkhDc3XeU0x&YOUgr2T_bi(V!wB&gai~s)GzeQ1|&k!(}(Q3WDb)_9u`J?FFwd|wk z&oap6=ccl~Jc0+q6J>Zcxw~N?j1!yu!WB5eJ;;~n42ZvIfUF4(I4T4W>IP9CdyTnK z%PNrJ1eatL_GUb66%YNQw1|BzJN<{?05kh0Xx9=>dbn=ISOg)vI{_Q}h+53E@(h09 zZ0>+__`W^{CBu+j7y`r%BcC%~^+hv9rv&b!MfnIl*LhwLPhDFKSlcbO&RI}09Rl^} zORV2vjDH^*P|nyV<{NAf2&uLvm=qE6}~OBMrG0yAEPOJBeOg%bX-#k?bW}W z>f*oN%5nSsxI2d;0l-X~-pQ!-BOjk=KE%?EB5yGl6_G!Sa^M|z;-Aqe2)<>Q*&P7` z--OfLr;|b|FXIXtj|mxbIwHx`Bl>iGf!TM%!`T08+q6aF(QQ6o?nmwiR;ZwjT?kHW zMd_wYJ4Pt(a*VFvUIT_HX+VWB!HhXDo5ya-gkoeVsp^!j4gU)Hy`SToZnRksj*~8JpQR`~}Dk7bI6`-sd{Q zS`50+d~-^sBqT2;iBSj6b1OyLwn}um;kcc_mA()4iA=l2L|{QrBVJR=CM{%qd}KjsVQo2^0T@S5lgs3)r_%=tx%=jG@X12QZQO_RSI-OH%@(R1hCMFIoQz8%9&;R(&|i}P?^4P_GAz>ut)zm0Ik zz;|r=UMXC9T2jGBVHlCmMvaP063^F%)v+FVPu#O^MuEyP^gYGk2^++5-f+I^KY3Ct zeE|MHrmnF&v#x1oV%xTDdt%$Rtw}Pm?JKrz+qP}ny5GE?p7{l5t<$S&ckk+5h2v?C zS^{s=_}Vl&^npzVm_Hsnh>wqI1_n9A*ZCc1q{8X+ClFmFyIcI?5-G=YJYw)fM2y*b zx3#8y(S4K;oxlk-G#4_GUt2mY$F$glcVzJ&lGeQf-bX)Vt>$twiAl3B?YzGs`F3+1 z<6~ZZUh_7An8-wC4BFloPk$}+&|ZefHjuTPAC&d+$JYtF->8Dj)EZ!~0hVb7Pd*Jw z7Zv&B;jKuP3LK7f$H@K(_Fca)I~Hkt*MHo3gi#-+(Z=tj=)+g3(KTF&d>3C-cUo^L z@ewFksW0akW52TZdFp9;o)mu&xZ}A`9c?lP_p1@(vaY|_AOlS3^;EmTPn~u7vHKD) z*@h~4eYt<=e|XN0tJQZ7lWYHo^?V^j!_J~i-UqD3Yc-6{b?ss`ETmIFVi@*M9F1;~ z3>7}wElXwlBue$%k~~s14YpnBN6i6?qS&3AWDpR@KG{1aB%6u`7s=Rc_!+vz$5`~1 z(lgHGFD6+ynjjNZ4~(I|D)x+Icuh~^i_=@RVc}<-wF)!5BfhXZcgIGdn-3rFr zlqNx1yqG3E%hb~GdA^jen;VRp{Q%@Y{D_vK5f5OkN0?BR(vM}2ttG{M#p$9tu z5G=eWXFe5(&(%C*meBWg=DfMSSsqf`T#v-$7;-Q~LmzNvNB3BvaFSF^zbYK%)wNWm zY=iLnd(EADz>7Yf-=y%Kf-7vEXPI_~kFZSew-}VeEb@Wb)EK!`KxN2Plxb9d`#){p zU@ALOda_AO`SHowRaMB9s}hRWEN{=UX&cBaCsO}-Bx;+np_;n2Y0j`ftD2E1<{JrPC(SXu7v7L;33lQ@>jvIlwrv3p@XTE=}ICN7zwPt7AOCvb99U$Ap25 z)Co!M(4EXA5?i*WkW|=7l$m+JFT*4U)!G^IiR}CigrrwBYHe@KMW#3I1fB-mbRJK7 zuU{CO4C#Ru%>IHgWZE(^Imx2BIK{5LYR3GQfer9o_Qm%MJ@l00eSz=vWAp3@NS_;C zo04d`)boG(Tj)NOq28w6xfd?Ib-C^IIdQuUj~n?bH>q*8TRoqkIewmxsam$&xxs#g zJrLTUIU|2#wZ>r;_JaM*_zmzjLmDBeN>f}Fa8Fw=7H?FlOsD6!1;{hIz2;`yA93!w zXzx0HvS1zJPhdAji)WwGyJe5nCo&_XL}14u7{4u8M;pi$G#JKYRaGaNw3>D9;dslS z2>JOHD9bcllm?;P6-#9p)*9aXMcnI_rCvQHU!cMRI{7PUA?QHI4V@Gi$WG^`)%@xW z<1l)mk3We$wsIt&LvQTbL>CAA%>DqOo70eG*jV*0YZE zbf0{^qH-h%J@E+|djB2;LQ1DcZDYywqbvR(!!%UVClNg<#&K=-x(LyT zes&2*Y1e@Z`=~t_m2KTYpeK`7^dj7p>j=iWUi}BU$<2d6j#$n6kGJUIh{i&fEog}h z-rSt9CmKduOehI_IpLdSbg8#_Qx<{2tBt@p*DQoFxM=%8a%1^A(JMzsb5>mf$y zIGPQHLzKoJ4dua62Rn#J4z2S!Ei&Ty`F3RU(Eh|$2*~mITR}8?f%c?!N~a0MiW_vc zUlIEZD6Thm-OPR1Z1U%MJtD^9cnD0a?NaUo!ykT!TSiWWtlDN-tspXOh0eW;LTe