From 41bbb5bec2c717daf2e0e5c21e9cfb302889c45e Mon Sep 17 00:00:00 2001 From: Heath Volmer Date: Tue, 21 Mar 2017 08:54:41 -0600 Subject: [PATCH] Combined projects into one solution --- Essentials/PepperDashEssentials.sln | 29 ++ .../PepperDashEssentials/HttpApiHandler.cs | 486 +++++++++--------- .../PepperDashEssentials.csproj | 4 - .../PepperDashEssentials.projectinfo | Bin 1986 -> 1944 bytes 4 files changed, 272 insertions(+), 247 deletions(-) diff --git a/Essentials/PepperDashEssentials.sln b/Essentials/PepperDashEssentials.sln index a512f634..425d6add 100644 --- a/Essentials/PepperDashEssentials.sln +++ b/Essentials/PepperDashEssentials.sln @@ -2,6 +2,23 @@ Microsoft Visual Studio Solution File, Format Version 10.00 # Visual Studio 2008 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PepperDashEssentials", "PepperDashEssentials\PepperDashEssentials.csproj", "{1BED5BA9-88C4-4365-9362-6F4B128071D3}" + ProjectSection(ProjectDependencies) = postProject + {892B761C-E479-44CE-BD74-243E9214AF13} = {892B761C-E479-44CE-BD74-243E9214AF13} + {9199CE8A-0C9F-4952-8672-3EED798B284F} = {9199CE8A-0C9F-4952-8672-3EED798B284F} + {A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5} = {A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PepperDash_Essentials_Core", "..\..\essentials-core\PepperDashEssentialsBase\PepperDashEssentialsBase\PepperDash_Essentials_Core.csproj", "{A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Essentials Devices Common", "..\..\essentials-devices-common\Essentials Devices Common\Essentials Devices Common\Essentials Devices Common.csproj", "{892B761C-E479-44CE-BD74-243E9214AF13}" + ProjectSection(ProjectDependencies) = postProject + {A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5} = {A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Essentials_DM", "..\..\essentials-dm\Essentials_DM\Essentials_DM\Essentials_DM.csproj", "{9199CE8A-0C9F-4952-8672-3EED798B284F}" + ProjectSection(ProjectDependencies) = postProject + {A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5} = {A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5} + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,6 +30,18 @@ Global {1BED5BA9-88C4-4365-9362-6F4B128071D3}.Debug|Any CPU.Build.0 = Debug|Any CPU {1BED5BA9-88C4-4365-9362-6F4B128071D3}.Release|Any CPU.ActiveCfg = Release|Any CPU {1BED5BA9-88C4-4365-9362-6F4B128071D3}.Release|Any CPU.Build.0 = Release|Any CPU + {A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}.Release|Any CPU.Build.0 = Release|Any CPU + {892B761C-E479-44CE-BD74-243E9214AF13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {892B761C-E479-44CE-BD74-243E9214AF13}.Debug|Any CPU.Build.0 = Debug|Any CPU + {892B761C-E479-44CE-BD74-243E9214AF13}.Release|Any CPU.ActiveCfg = Release|Any CPU + {892B761C-E479-44CE-BD74-243E9214AF13}.Release|Any CPU.Build.0 = Release|Any CPU + {9199CE8A-0C9F-4952-8672-3EED798B284F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9199CE8A-0C9F-4952-8672-3EED798B284F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9199CE8A-0C9F-4952-8672-3EED798B284F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9199CE8A-0C9F-4952-8672-3EED798B284F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Essentials/PepperDashEssentials/HttpApiHandler.cs b/Essentials/PepperDashEssentials/HttpApiHandler.cs index f3dca1e6..0a757999 100644 --- a/Essentials/PepperDashEssentials/HttpApiHandler.cs +++ b/Essentials/PepperDashEssentials/HttpApiHandler.cs @@ -1,266 +1,266 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using Crestron.SimplSharp.CrestronIO; -using Crestron.SimplSharp.Net.Http; +//using System; +//using System.Collections.Generic; +//using System.Linq; +//using System.Text; +//using Crestron.SimplSharp; +//using Crestron.SimplSharp.CrestronIO; +//using Crestron.SimplSharp.Net.Http; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; +//using Newtonsoft.Json; +//using Newtonsoft.Json.Linq; -using PepperDash.Essentials.Core; -using PepperDash.Essentials.Core.Http; -using PepperDash.Core; +//using PepperDash.Essentials.Core; +//using PepperDash.Essentials.Core.Http; +//using PepperDash.Core; -namespace PepperDash.Essentials -{ - public class EssentialsHttpApiHandler - { - string ConfigPath; - string PresetsPathPrefix; - EssentialsHttpServer Server; +//namespace PepperDash.Essentials +//{ +// public class EssentialsHttpApiHandler +// { +// string ConfigPath; +// string PresetsPathPrefix; +// EssentialsHttpServer Server; - /// - /// - /// - /// HTTP server to attach to - /// The full path to configuration file - /// The folder prefix for the presets path, eq "\HTML\presets\" - public EssentialsHttpApiHandler(EssentialsHttpServer server, string configPath, string presetsPathPrefix) - { - if (server == null) throw new ArgumentNullException("server"); - Server = server; - ConfigPath = configPath; - PresetsPathPrefix = presetsPathPrefix; - server.ApiRequest += Server_ApiRequest; - } +// /// +// /// +// /// +// /// HTTP server to attach to +// /// The full path to configuration file +// /// The folder prefix for the presets path, eq "\HTML\presets\" +// public EssentialsHttpApiHandler(EssentialsHttpServer server, string configPath, string presetsPathPrefix) +// { +// if (server == null) throw new ArgumentNullException("server"); +// Server = server; +// ConfigPath = configPath; +// PresetsPathPrefix = presetsPathPrefix; +// server.ApiRequest += Server_ApiRequest; +// } - void Server_ApiRequest(object sender, Crestron.SimplSharp.Net.Http.OnHttpRequestArgs args) - { - try - { - var path = args.Request.Path.ToLower(); +// void Server_ApiRequest(object sender, Crestron.SimplSharp.Net.Http.OnHttpRequestArgs args) +// { +// try +// { +// var path = args.Request.Path.ToLower(); - if (path == "/api/config") - HandleApiConfig(args); - else if (path.StartsWith("/api/presetslist/")) - HandleApiPresetsList(args); - else if (path == "/api/presetslists") - HandleApiGetPresetsLists(args.Request, args.Response); - else - { - args.Response.Code = 404; - return; - } - args.Response.Header.SetHeaderValue("Access-Control-Allow-Origin", "*"); - args.Response.Header.SetHeaderValue("Access-Control-Allow-Methods", "GET, POST, PATCH, PUT, DELETE, OPTIONS"); - } - catch (Exception e) - { - Debug.Console(1, "Uncaught HTTP server error: \n{0}", e); - args.Response.Code = 500; - } - } +// if (path == "/api/config") +// HandleApiConfig(args); +// else if (path.StartsWith("/api/presetslist/")) +// HandleApiPresetsList(args); +// else if (path == "/api/presetslists") +// HandleApiGetPresetsLists(args.Request, args.Response); +// else +// { +// args.Response.Code = 404; +// return; +// } +// args.Response.Header.SetHeaderValue("Access-Control-Allow-Origin", "*"); +// args.Response.Header.SetHeaderValue("Access-Control-Allow-Methods", "GET, POST, PATCH, PUT, DELETE, OPTIONS"); +// } +// catch (Exception e) +// { +// Debug.Console(1, "Uncaught HTTP server error: \n{0}", e); +// args.Response.Code = 500; +// } +// } - /// - /// GET will return the running configuration. POST will attempt to take in a new config - /// and restart the program. - /// - void HandleApiConfig(OnHttpRequestArgs args) - { - var request = args.Request; - if (request.Header.RequestType == "GET") - { - if (File.Exists(ConfigPath)) - { - Debug.Console(2, "Sending config:{0}", ConfigPath); - args.Response.Header.ContentType = EssentialsHttpServer.GetContentType(new FileInfo(ConfigPath).Extension); - args.Response.ContentStream = new FileStream(ConfigPath, FileMode.Open, FileAccess.Read); - } - } - else if (request.Header.RequestType == "POST") - { - Debug.Console(2, "Post type: '{0}'", request.Header.ContentType); +// /// +// /// GET will return the running configuration. POST will attempt to take in a new config +// /// and restart the program. +// /// +// void HandleApiConfig(OnHttpRequestArgs args) +// { +// var request = args.Request; +// if (request.Header.RequestType == "GET") +// { +// if (File.Exists(ConfigPath)) +// { +// Debug.Console(2, "Sending config:{0}", ConfigPath); +// args.Response.Header.ContentType = EssentialsHttpServer.GetContentType(new FileInfo(ConfigPath).Extension); +// args.Response.ContentStream = new FileStream(ConfigPath, FileMode.Open, FileAccess.Read); +// } +// } +// else if (request.Header.RequestType == "POST") +// { +// Debug.Console(2, "Post type: '{0}'", request.Header.ContentType); - // Make sure we're receiving at least good json - Debug.Console(1, "Receving new config"); - if (GetContentStringJson(args) == null) - return; +// // Make sure we're receiving at least good json +// Debug.Console(1, "Receving new config"); +// if (GetContentStringJson(args) == null) +// return; - //---------------------------- try to move these into common method - // Move current file aside - var bakPath = ConfigPath + ".bak"; - if (File.Exists(bakPath)) - File.Delete(bakPath); - File.Move(ConfigPath, bakPath); +// //---------------------------- try to move these into common method +// // Move current file aside +// var bakPath = ConfigPath + ".bak"; +// if (File.Exists(bakPath)) +// File.Delete(bakPath); +// File.Move(ConfigPath, bakPath); - // Write the file - using (FileStream fs = File.Open(ConfigPath, FileMode.OpenOrCreate)) - using (StreamWriter sw = new StreamWriter(fs)) - { - try - { - sw.Write(args.Request.ContentString); - } - catch (Exception e) - { - string err = string.Format("Error writing received config file:\r{0}", e); - CrestronConsole.PrintLine(err); - ErrorLog.Warn(err); - // Put file back - File.Move(ConfigPath + ".bak", ConfigPath); - args.Response.Code = 500; - return; - } - } +// // Write the file +// using (FileStream fs = File.Open(ConfigPath, FileMode.OpenOrCreate)) +// using (StreamWriter sw = new StreamWriter(fs)) +// { +// try +// { +// sw.Write(args.Request.ContentString); +// } +// catch (Exception e) +// { +// string err = string.Format("Error writing received config file:\r{0}", e); +// CrestronConsole.PrintLine(err); +// ErrorLog.Warn(err); +// // Put file back +// File.Move(ConfigPath + ".bak", ConfigPath); +// args.Response.Code = 500; +// return; +// } +// } - // If client says "yeah, restart" and has a good token - // Restart program - string consoleResponse = null; - var restart = CrestronConsole.SendControlSystemCommand("progreset -p:" + - InitialParametersClass.ApplicationNumber, ref consoleResponse); - if (!restart) Debug.Console(0, "CAN'T DO THAT YO: {0}", consoleResponse); - } - } +// // If client says "yeah, restart" and has a good token +// // Restart program +// string consoleResponse = null; +// var restart = CrestronConsole.SendControlSystemCommand("progreset -p:" + +// InitialParametersClass.ApplicationNumber, ref consoleResponse); +// if (!restart) Debug.Console(0, "CAN'T DO THAT YO: {0}", consoleResponse); +// } +// } - void HandleApiPresetsList(OnHttpRequestArgs args) - { - var listPath = PresetsPathPrefix + args.Request.Path.Remove(0, 17); - Debug.Console(2, "Checking for preset list '{0}'", listPath); +// void HandleApiPresetsList(OnHttpRequestArgs args) +// { +// var listPath = PresetsPathPrefix + args.Request.Path.Remove(0, 17); +// Debug.Console(2, "Checking for preset list '{0}'", listPath); - if (args.Request.Header.RequestType == "GET") - { - if (File.Exists(listPath)) - { - Debug.Console(2, "Sending presets file:{0}", listPath); - args.Response.Header.ContentType = EssentialsHttpServer.GetContentType(new FileInfo(listPath).Extension); - args.Response.ContentStream = new FileStream(listPath, FileMode.Open, FileAccess.Read); - } - } - else if (args.Request.Header.RequestType == "POST") - { - // Make sure we're receiving at least good json - Debug.Console(1, "Receving new presets"); - if (GetContentStringJson(args) == null) - return; +// if (args.Request.Header.RequestType == "GET") +// { +// if (File.Exists(listPath)) +// { +// Debug.Console(2, "Sending presets file:{0}", listPath); +// args.Response.Header.ContentType = EssentialsHttpServer.GetContentType(new FileInfo(listPath).Extension); +// args.Response.ContentStream = new FileStream(listPath, FileMode.Open, FileAccess.Read); +// } +// } +// else if (args.Request.Header.RequestType == "POST") +// { +// // Make sure we're receiving at least good json +// Debug.Console(1, "Receving new presets"); +// if (GetContentStringJson(args) == null) +// return; - //---------------------------- try to move these into common method - // Move current file aside - var bakPath = listPath + ".new"; - Debug.Console(2, "Moving presets file to {0}", bakPath); - if(File.Exists(bakPath)) - File.Delete(bakPath); - File.Move(listPath, bakPath); +// //---------------------------- try to move these into common method +// // Move current file aside +// var bakPath = listPath + ".new"; +// Debug.Console(2, "Moving presets file to {0}", bakPath); +// if(File.Exists(bakPath)) +// File.Delete(bakPath); +// File.Move(listPath, bakPath); - Debug.Console(2, "Writing new file"); - // Write the file - using (FileStream fs = File.OpenWrite(listPath)) - using (StreamWriter sw = new StreamWriter(fs)) - { - try - { - Debug.Console(2, "Writing {1}, {0} bytes", args.Request.ContentString.Length, listPath); - sw.Write(args.Request.ContentString); - } - catch (Exception e) - { - string err = string.Format("Error writing received presets file:\r{0}", e); - CrestronConsole.PrintLine(err); - ErrorLog.Warn(err); - // Put file back - File.Move(listPath + ".bak", listPath); - args.Response.Code = 500; - return; - } - } - } - } +// Debug.Console(2, "Writing new file"); +// // Write the file +// using (FileStream fs = File.OpenWrite(listPath)) +// using (StreamWriter sw = new StreamWriter(fs)) +// { +// try +// { +// Debug.Console(2, "Writing {1}, {0} bytes", args.Request.ContentString.Length, listPath); +// sw.Write(args.Request.ContentString); +// } +// catch (Exception e) +// { +// string err = string.Format("Error writing received presets file:\r{0}", e); +// CrestronConsole.PrintLine(err); +// ErrorLog.Warn(err); +// // Put file back +// File.Move(listPath + ".bak", listPath); +// args.Response.Code = 500; +// return; +// } +// } +// } +// } - void HandleApiGetPresetsLists(HttpServerRequest request, HttpServerResponse response) - { - if (request.Header.RequestType != "GET") - { - response.Code = 404; // This should be a 405 with an allow header - return; - } +// void HandleApiGetPresetsLists(HttpServerRequest request, HttpServerResponse response) +// { +// if (request.Header.RequestType != "GET") +// { +// response.Code = 404; // This should be a 405 with an allow header +// return; +// } - if (Directory.Exists(PresetsPathPrefix)) - { - //CrestronConsole.PrintLine("Parsing presets directory"); - List files = Directory.GetFiles(PresetsPathPrefix, "*.json") - .ToList().Select(f => Path.GetFileName(f)).ToList(); - if (files.Count > 0) - files.Sort(); - var json = JsonConvert.SerializeObject(files); - response.Header.ContentType = "application/json"; - response.ContentString = json; - } +// if (Directory.Exists(PresetsPathPrefix)) +// { +// //CrestronConsole.PrintLine("Parsing presets directory"); +// List files = Directory.GetFiles(PresetsPathPrefix, "*.json") +// .ToList().Select(f => Path.GetFileName(f)).ToList(); +// if (files.Count > 0) +// files.Sort(); +// var json = JsonConvert.SerializeObject(files); +// response.Header.ContentType = "application/json"; +// response.ContentString = json; +// } - // //CrestronConsole.PrintLine("Found {0} files", files.Count); - // JObject jo = new JObject(); - // JArray ja = new JArray(); +// // //CrestronConsole.PrintLine("Found {0} files", files.Count); +// // JObject jo = new JObject(); +// // JArray ja = new JArray(); - // foreach (var filename in files) - // { - // try - // { - // using (StreamReader sr = new StreamReader(filename)) - // { - // JObject tempJo = JObject.Parse(sr.ReadToEnd()); - // if (tempJo.Value("content").Equals("presetsList")) - // { - // var jItem = new JObject(); // make a new object - // jItem.Add("Name", tempJo["name"]); - // jItem.Add("File", filename); - // jItem.Add("Url", Uri.EscapeUriString(new Uri( - // filename.Replace("\\html", "") - // .Replace("\\HTML", "") - // .Replace('\\', '/'), UriKind.Relative).ToString())); - // ja.Add(jItem); // add to array - // } - // else - // CrestronConsole.PrintLine("Cannot use presets file '{0}'", filename); - // } - // } - // catch - // { - // // ignore failures - maybe delete them - // CrestronConsole.PrintLine("Unable to read presets file '{0}'", filename); - // } - // } - // jo.Add("PresetChannelLists", ja); - // //CrestronConsole.PrintLine(jo.ToString()); - // response.Header.ContentType = "application/json"; - // response.ContentString = jo.ToString(); - //} - //else - // CrestronConsole.PrintLine("No presets files in directory"); - } +// // foreach (var filename in files) +// // { +// // try +// // { +// // using (StreamReader sr = new StreamReader(filename)) +// // { +// // JObject tempJo = JObject.Parse(sr.ReadToEnd()); +// // if (tempJo.Value("content").Equals("presetsList")) +// // { +// // var jItem = new JObject(); // make a new object +// // jItem.Add("Name", tempJo["name"]); +// // jItem.Add("File", filename); +// // jItem.Add("Url", Uri.EscapeUriString(new Uri( +// // filename.Replace("\\html", "") +// // .Replace("\\HTML", "") +// // .Replace('\\', '/'), UriKind.Relative).ToString())); +// // ja.Add(jItem); // add to array +// // } +// // else +// // CrestronConsole.PrintLine("Cannot use presets file '{0}'", filename); +// // } +// // } +// // catch +// // { +// // // ignore failures - maybe delete them +// // CrestronConsole.PrintLine("Unable to read presets file '{0}'", filename); +// // } +// // } +// // jo.Add("PresetChannelLists", ja); +// // //CrestronConsole.PrintLine(jo.ToString()); +// // response.Header.ContentType = "application/json"; +// // response.ContentString = jo.ToString(); +// //} +// //else +// // CrestronConsole.PrintLine("No presets files in directory"); +// } - /// - /// Simply does what it says - /// - JObject GetContentStringJson(OnHttpRequestArgs args) - { - //var content = args.Request.ContentString; - //Debug.Console(1, "{0}", content); +// /// +// /// Simply does what it says +// /// +// JObject GetContentStringJson(OnHttpRequestArgs args) +// { +// //var content = args.Request.ContentString; +// //Debug.Console(1, "{0}", content); - try - { - // just see if it parses properly - return JObject.Parse(args.Request.ContentString); - } - catch (Exception e) - { - string err = string.Format("JSON Error reading config file:\r{0}", e); - CrestronConsole.PrintLine(err); - ErrorLog.Warn(err); - args.Response.Code = 400; // Bad request - return null; - } - } - } -} \ No newline at end of file +// try +// { +// // just see if it parses properly +// return JObject.Parse(args.Request.ContentString); +// } +// catch (Exception e) +// { +// string err = string.Format("JSON Error reading config file:\r{0}", e); +// CrestronConsole.PrintLine(err); +// ErrorLog.Warn(err); +// args.Response.Code = 400; // Bad request +// return null; +// } +// } +// } +//} \ No newline at end of file diff --git a/Essentials/PepperDashEssentials/PepperDashEssentials.csproj b/Essentials/PepperDashEssentials/PepperDashEssentials.csproj index a74e15fe..1373e284 100644 --- a/Essentials/PepperDashEssentials/PepperDashEssentials.csproj +++ b/Essentials/PepperDashEssentials/PepperDashEssentials.csproj @@ -75,10 +75,6 @@ ..\..\..\essentials-devices-common\Essentials Devices Common\Essentials Devices Common\bin\Essentials Devices Common.dll True - - False - ..\..\..\essentials-http-server\EssentialsHttpServer\bin\EssentialsHttpServer.dll - False diff --git a/Essentials/PepperDashEssentials/PepperDashEssentials.projectinfo b/Essentials/PepperDashEssentials/PepperDashEssentials.projectinfo index e4fe4b785b0cec819700ecbccb987ab552588547..622ba56ec3069d4a425a5dc1027187d14915eb33 100644 GIT binary patch delta 1811 zcmV+u2kiL5510>-g@5wVqqbhtFH`#JWxiVF_0z1GpEgatYzt~bt!Kku<@6Q(IF}z6 z^kZ*l_rdngz3si-H#-N9?(aUje}8;`cmMvwdk5P)pFY~zp>}g>ck<}>{e8b`^1Atb zf8Y6KRW9=S_x*jJ=FQu-TK&Gi?^RX5EtVI*@9&%2&VJwD*MD{V`~JQ$bbjC8cTz0l zUyY}$A5g!A9rnw*`ssYyo-NO-XGNJWvqk>1gi{oqm2_WF_k`A2^R%ejYcmtCubVbs zybzQI=uY@w)Y;-}_9nZyu@#L&=I3}eE83!3W+etLpPf{T6;WXJkib=5}&Vs@3(I>RDCJ2&Io68OGoH=$DK>`l47Ci}m7JQ7^8t zI{!&(K?H$VjCXb((*O4!67VnA?P}e=%-WwFPNg2c$d<)<-n0(Ad-UmsN!MY2krm5h z`fxERuid-*^o=(k(f4O%Nv(nb(|^1ByZ1l+s7IGBL4UqYut37e!QQ!+4=o!dY&EZOsDrIlYckf`bJG;%a7?8nS+yd~| zoeR_7|H~%e!L26Xw4LYmGH=P4EY{0nn!zj?;eS)w-TO5E^wWF$4+$Ac0da(EK{2;r7+`BWK?0-!5@85f{^I&gA%6{+Oe*R!L-?`0PSdhUq z+yd~|oCe$9|J!C@FPs4fDiwFJNn!cA_9FZA)7?DZ`*iZ)Am5wZ-D+|=Ly+h*WiI0FvoNmb`B$yLwF*VoHwH~|N{_w!G84u7VT zgY4j7=U|pic0YY^aPPtN{NUka_kLg@Zh#oj{}ym>qW=xu{lAU;gTeRj5A;K-?>{`x zcV^_jOg??^Y4&huZ%V3q=l-WVpFTLx&-W*Bs{4QfV&4MX?TPL8^8Yp(cLHw@X$Lhz z?t|IAPj?>9_Q`{vJ$Se?n^7oyet)p@aCbVTuEz)2(@!V&C%Y6^?d{#mve`ZQlpL3vC!zy44Bl>r{`DrK z)9L@)CZrQ<4~(Ic>$sO^d%FijrrD>vd!O!|pFhkVJ~*G;&+pBq=lj!#w{4h;XsY8D zaKGjx{J%8QvD=B3oxgTcU$0uE-dFSMvt^st=h?KQnP#*72M>3%gHLClo`3paHk;lf z-(;VRWxlsRrA&lB3%3ItOvWw1-!vJw>-GO_bJ7W#y+N#-wptvwZCy;(6weII3sGs4 z5e6B5xdhU2d*H#`+@g#3n424V{(ss0>~#WYH;`}VC4nE9l`Nk<*vlt7Ic4W4txYMp zPao_YO!5bx?(g59O=t00iGvKIg_{B2elFtu{l9GnIuWx&|3!Y)Qf9I`@2puooRaRi zKfAXxBWlfNdwaV(yR?LJe*WnIqdPF6j~W1r0=qqtT_68%qi!esbtu2e z&r7VbSIYsllHVhrJ)cb`*}?vFI(x8t|Ni9R!-M_&(+B$p2a_OaeH*X=^=|?E_S7GL z?(_d`v(br$-4I^?#Pf|h{(NV8f9L*emQQB~8D$J+`;!Ov_jVuL-`Sl`CJzQCV-RXE z7q@_Y`?(nG^8X!E(fPnmOechP<9V93*?5+t-~vb=k^5{~um(1JBVU006I> B0?_~f delta 1874 zcmV-Y2d(&+55fhL^VKS^pJvVcv}y8XThLe3d^Y@5PG8ZFbNO*WKlXNZ zA8ha3+uqxGv-9B5{ryL~yW_q62cJH?M<0LsXlIAo&8gkVqu=-U{i@09=J)-5=a*Hv z$m`$t_kEf-Z`*41`~JRHRsFVDUi`klZ*DvLeShB=3PYbxihpJNtMPR81Hz!N<9=CJ zKb=q8v*mg9tSIwkw#a|hv5O+M5=06@gb+Myo)&d`ZP9#v-L(1Qg{A`Qf5ytDI= z{=fH-fPcAeSL^m=*8XfWGWGREwk*!`rgezkqfa+5f)e11tXLk?hl@#h?cUv|Z@f8* zzCSBVY84Ef{@dN#-$TzG3Ux{IZGr_HKb?GfFrDmW`+vKW{NUl<NxK#rg0m&G)HybNm%4wG6`;+~>`wz41{L|fsJNF-+?_~MC{rv~` zCg-y~pMR9^0bSm?eIGYW#iRG=`iDAa{h9gx=%ZJ8!^7u4f62(q)u*?ct1rR{n#|7c zXVdfSU}rkLH<=tfIN#fy<&%SlySsY_lik^ECdhycX5|)uzwWG<{{CM(6%TGT6{qby zua|jC=4Y{97Sjxd%m}1aMfsyA7=qN#0US)tEx>=xsp<6k|Jupf-MQ85yvi3#1 zXMgWu{^`TL>FnP9oqYP~z3Ic92b263lM})X=H?dAzvkS8o&LXfYIbimHD8^Dv$AvW z@E&pW&UCUf*}s49!Onxd85xDWd;9r=-G6-NHnUB|9go)7}TFsb^em#uB?20y_|OBVE2Ab)S6BXvV()2gIPA&{q(`X zy$93tgNKvd`+*t10b(cyH^aSY5^m`3|Gg8@iS-@O-yZ`B>A(N*Jl~m-<2m{C!Kc~7 zoxLg9)1CXD?tJ>-JU`!`#Odz?3V+Cc3vjn5yWh+Id#T-t);;tc)Cl3Tds)6m?*9GR zUcP(qa3{O};NW0-{$TgPYPOX2d~-n}fF-J?&*8IxhWLwF@eDL65n0LGZVkjjy!~L4m@&Edy)@~>6 zb}sixeZ6Y2F0-0npDo+GKF_8dy)`5HJlxF=KAnAf{^^6+YOv^36-!v_^>-GP&vwySKiMzewtedu49Jg&R=P=O+#_RB1N@zWuDk`}^Rz_m;KLfq4{@+Xd zPTU>laPoJ#qdEm+dwb-e?vNvNfA8M?-Sa%Vx3{~qODlcn=bsKRzXKBnc{c;QJ-J;U z|L>)9C&YHhzsk?ce1D3ym;t4e-#b4)$Y+yDcCbI4&K~UEzdw2S@L)gx^uhkY!6a~_ zZUZ)$hg$%@{X7i!`TyQ|=|tRaFt2~&`9@oCzB9eQbAL9=r?Z2M@)NWD$%FfQyAST~ z>`o_>2LsbG2sN0MTfn~ktPFPf|F%i#d|;=j6Q;Y7J5c(zG|0Ta<^wCe|b#bl>tu(TA*~&ow MAGzn07D^`o06e}lnE(I)