這是使用新竹物流的範例程式 來源是UNT後台Web專案 * 新竹物流取得配號API必須先在專案加入WEB服務參考 (此專案命名是HctService) * 取得配號是使用 HctService.Service1SoapClient -> TransData_Json() 來取得 回傳資料因為有 面單(出貨標籤) 圖檔的Hex字串,所以回應訊息很大,建議一次僅處理兩筆出貨單 * 本範例程式有處理Hex字串轉圖檔程式 * 取得貨況的功能。是另一組專用API -> https://www.hct.com.tw/phone/searchGoods_Main_Xml.ashx * POST參數是xml再加密為base64字串 * Response是base64字串,需解密為xml * 本程式範例有相關的使用與加解密功能 參考 GetDeliveryStatus <%@ WebHandler Language="C#" Class="GetHctShippingData" %> using System; using System.Web; using System.Data; using System.IO; using HctService; using System.Drawing; using System.Drawing.Imaging; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using Dapper; public class GetHctShippingData : IHttpHandler { List mailMsgs = new List(); bool IsNoData = false; List ignoreOIds = new List(); string[] Brands = new string[4] { "BE", "BM", "86", "UNT"}; // 20240628 搬倉改ID string[] Companies = new string[4] { "05721540016", "05721540024", "05721540008", "05721540008" }; string[] Pwds = new string[4] { "XXXXXXXX", "XXXXXXXX", "XXXXXXXX", "XXXXXXXX" }; int CurrentBrandIdx = 0; int DealingCount = 0; public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/plain"; string fun = context.Request.QueryString["fun"]; //if (string.IsNullOrEmpty(fun)) //{ // context.Response.Write("fun"); // return; //} if (context.Request.QueryString["fun"] == "TestFunction") { TestFunction(context); return; } else if (context.Request.QueryString["fun"] == "CheckRefrigerationShipping") { context.Response.Write("此功能於20240701關閉"); context.Response.End(); //檢查未出貨的訂單 是否有聯運費用 DB.OrderMain od = new DB.OrderMain(); od.StockStatus = DB.OrderMain.EN.StockStatus.正常出貨; od.PayMethod = DB.OrderMain.EN.PayMethod.B86_陶選物; od.Create_Date__Start = DateTime.Now.AddDays(-3); od.ShippingWarning__Like = "%冷凍運輸%"; //od.PackingListStatus = DB.OrderMain.EN.PackingListStatus.無出貨單; //mailMsgs.Add(od.QuerySql()); DataTable dt = od.GetQueryDT(); foreach (DataRow row in dt.Rows) { od = new DB.OrderMain(row); if (od.ShippingWarning.Contains("聯運費用") || od.PackingListStatus == DB.OrderMain.EN.PackingListStatus.已出貨) { continue; } string fullAddress = od.County_Name + od.City_Name + od.Address; string restultOf聯運費用 = this.Get冷凍聯運(fullAddress); if (restultOf聯運費用.StartsWith("聯運費用")) { od.ShippingWarning = od.ShippingWarning + ";" + restultOf聯運費用; od.Shipping_Memo = od.Shipping_Memo + ";" + restultOf聯運費用; mailMsgs.Add("陶選物訂單 " + od.Id + " 冷凍運輸-" + restultOf聯運費用); } else { od.ShippingWarning = od.ShippingWarning + ";無聯運費用"; mailMsgs.Add("陶選物訂單 " + od.Id + " 冷凍運輸-無聯運費用"); } od.Update(-1, DBC: SHOPUNT.CST.DBC.DBC); } if (mailMsgs.Count > 0) { string mailMessage = string.Join("\r\n", mailMsgs); context.Response.Write(mailMessage); SendNotifyMail("新竹物流API冷凍物流檢查", mailMessage); } else { context.Response.Write("No Data."); } return; } else if (context.Request.QueryString["fun"] == "GetDeliveryStatus") { // 早晚 6:00 各跑一次 // 一次最多100筆 for (int i = 0; i < 5; i++) { context.Response.Write("第" + (i+1) + "次取得貨況 " + DateTime.Now.ToString() + "\r\n"); GetDeliveryStatus(context); if (IsAllDeliveryStatusDone) { break; } } context.Response.Write("取得貨況結束 " + DateTime.Now.ToString() + "\r\n"); // 同步把一些舊資料清除 清出資料庫的空間 string sql = @" Select Top 50 Id into #tmpHctId From Hct_Log where ShippedTime < GETDATE()-180 and JsonResult <> '' order by Id update Hct_Log set JsonResult = '' where Id in (Select Id From #tmpHctId) and JsonResult <> '' drop table #tmpHctId "; context.Response.Write("清除舊資料 " + sql + "\r\n"); UW.SQL.executeSQL(sql); return; } //return; // ------------------------------------------------ for (int i = 0; i < Brands.Length; i++) { CurrentBrandIdx = i; mailMsgs.Add("----- 處理" + Brands[CurrentBrandIdx] + "開始 ----"); // 因為下載圖檔約 20K , webservice 傳輸限制是 65K (除非改 config) // 文件也要求最多5筆 所以就乾脆一次處理兩筆 IsNoData = false; for (int j = 0; j < 100; j++) { FetchData(context); if (IsNoData) break; } } //補跑沒有完成轉圖檔的 MakeImage(context); if (mailMsgs.Count > 0 && DealingCount > 0) { string mailMessage = string.Join("\r\n", mailMsgs); context.Response.Write(mailMessage); SendNotifyMail("新竹物流API取得配編結果通知", mailMessage); } } private bool IsAllDeliveryStatusDone = false; private void GetDeliveryStatus(HttpContext context) { string sql = @"SELECT TOP (20) OrderId,ShippingNo FROM [Hct_Log] (nolock) where ShippedTime < GETDATE()-1 and ShippedTime > GETDATE()-21 and ArriveDate is null and ReturnDate is null AND (ShipStatusTime is null or ShipStatusTime < GETDATE()-0.5) order by OrderId "; DataTable dt = UW.SQL.DTFromSQL(sql); if (dt.Rows.Count == 0) { IsAllDeliveryStatusDone = true; return; } string queryXml = @""; foreach (DataRow row in dt.Rows) { int OrderId = Convert.ToInt32(row["OrderId"]); queryXml += @"".Replace("{OrderId}", "TW" + OrderId); } queryXml += @""; string query = this.GetEncodedQuery(queryXml); string encodeXml = ""; using (System.Net.WebClient wc = new System.Net.WebClient()) { wc.Encoding = System.Text.Encoding.UTF8; encodeXml = wc.DownloadString("https://www.hct.com.tw/phone/searchGoods_Main_Xml.ashx?no=" + System.Uri.EscapeDataString(query) + "&v=2961316A807855944933AA82E525D71F"); } string resultXml = DecodeResultXml(encodeXml); //context.Response.Write("resultXml-" + resultXml + "\r\n"); System.Xml.XmlDocument xDoc = new System.Xml.XmlDocument(); xDoc.LoadXml(resultXml); foreach (System.Xml.XmlNode node in xDoc.DocumentElement.ChildNodes) { string orderId = node.Attributes["ordersid"].Value; context.Response.Write(orderId + ": " + node.OuterXml + "\r\n"); string FinalStatus = "配送中"; string FinalStatusTime = "配送中"; foreach (System.Xml.XmlNode subnode in node.ChildNodes) { string statusText = subnode.Attributes["status"].Value; FinalStatusTime = subnode.Attributes["wrktime"].Value; if (statusText.Contains("送達")) { FinalStatus = "送達"; } else if (statusText.Contains("已退回")) { FinalStatus = "退回"; } // 就抓第一筆 break; } int intOrderId = Convert.ToInt32(orderId.Replace("TW", "")); if (FinalStatus == "送達") { using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(SHOPUNT.CST.DBC.DBC)) { conn.Open(); conn.Execute(@"UPDATE Hct_Log Set ShipStatus=@ShipStatus, ArriveDate=@ArriveDate, ShipStatusTime=GETDATE() Where OrderId = @OrderId Update Packing_List_Main set TCatReturnDesc=@FinalStatus where Order_Id = @OrderId ", param: new { ShipStatus = node.OuterXml, ArriveDate = Convert.ToDateTime(FinalStatusTime), OrderId = intOrderId, FinalStatus }); } } else if (FinalStatus == "退回") { using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(SHOPUNT.CST.DBC.DBC)) { conn.Open(); conn.Execute(@"UPDATE Hct_Log Set ShipStatus=@ShipStatus, ReturnDate=@ReturnDate, ShipStatusTime=GETDATE() Where OrderId = @OrderId Update Packing_List_Main set TCatReturnDesc=@FinalStatus where Order_Id = @OrderId ", param: new { ShipStatus = node.OuterXml, ReturnDate = Convert.ToDateTime(FinalStatusTime), OrderId = intOrderId, FinalStatus }); } } else { using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(SHOPUNT.CST.DBC.DBC)) { conn.Open(); conn.Execute(@"UPDATE Hct_Log Set ShipStatus=@ShipStatus, ShipStatusTime=GETDATE() Where OrderId = @OrderId Update Packing_List_Main set TCatReturnDesc=@FinalStatus where Order_Id = @OrderId ", param: new { ShipStatus = node.OuterXml, OrderId = intOrderId, FinalStatus }); } } } //query = this.GetEncodedQuery("TW1674454"); //context.Response.Write(query + "\r\n"); //context.Response.Write("https://www.hct.com.tw/phone/searchGoods_Main.aspx?no=" + System.Uri.EscapeDataString(query) + "&v=2961316A807855944933AA82E525D71F" + "\r\n"); } private void MakeImage(HttpContext context) { DataTable dt = UW.SQL.DTFromSQL(@"Select OrderId,ShippingNo,JsonResult From Hct_Log where OrderId > (Select ISNULL(MAX(Id),0) - 500 From Hct_Log) and Is_MakeImage='N'"); foreach (DataRow row in dt.Rows) { string HctResultJson = row["JsonResult"].ToString(); LogisticsAPI.HctModel.TransDataResult result = Newtonsoft.Json.JsonConvert.DeserializeObject(HctResultJson); string orderid = row["OrderId"].ToString(); string shippingNo = row["ShippingNo"].ToString(); string imageHex = result.image; //把圖片轉成 image string fileName = orderid + "_" + shippingNo + ".jpg"; string savePath = SHOPUNT.DB.SysConfig.Path.LocalDataRoot() + "Hct\\" + fileName; byte[] byts = GetBytes(imageHex); Bitmap bmp = GetImage(byts); //20230629 新竹物流要求放大一下 1000 -> 1100 Bitmap newBmp = new Bitmap(1130, 1130); using (Graphics g = Graphics.FromImage(newBmp)) { g.DrawImage(bmp, 0, 0, 1130, 1130); } ImageCodecInfo jpgEncoder = GetEncoder(ImageFormat.Jpeg); System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality; EncoderParameters myEncoderParameters = new EncoderParameters(1); EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, 80L);//品質0到100分的中間值50分 myEncoderParameters.Param[0] = myEncoderParameter; //newBmp.Save(savePath, ImageFormat.Bmp); newBmp.Save(savePath, jpgEncoder, myEncoderParameters); bmp.Dispose(); newBmp.Dispose(); UW.SQL.executeSQL("Update Packing_List_Main Set ShippingNo='@ShippingNo', ShippingNo2='@fname' where Order_Id=@OrderId and Delete_TF is null" .Replace("@OrderId", orderid).Replace("@ShippingNo", shippingNo).Replace("@fname", fileName)); UW.SQL.executeSQL("Update Hct_Log Set Is_MakeImage='Y' where OrderId=@OrderId and ShippingNo='@ShippingNo'" .Replace("@OrderId", orderid).Replace("@ShippingNo", shippingNo)); mailMsgs.Add(orderid + "補轉圖檔成功."); } } private void TestFunction(HttpContext context) { string query = this.GetEncodedQuery("1046298050"); context.Response.Write(query + "\r\n"); context.Response.Write("https://www.hct.com.tw/phone/searchGoods_Main.aspx?no=" + System.Uri.EscapeDataString(query) + "&v=2961316A807855944933AA82E525D71F" + "\r\n"); /* 送貨地址:桃園市觀音區工業八路188號 到著站四碼:2308 到著站簡碼:31 到著站中文:平鎮 郵遞區號:328 聯運費用(起碼):150 聯運費用(百公斤):100 優勢困難配送: 送貨地址:台北市北投區自強街82號 到著站四碼:1247 到著站簡碼:23 到著站中文:北投 郵遞區號:112 聯運費用(起碼): 聯運費用(百公斤): 優勢困難配送: */ //string r = this.Get冷凍聯運("台北市北投區自強街82號"); } private void FetchData(HttpContext context) { //最多一次只處理 2 筆 string sql = @"Select top 2 Id,Order_Id,ShippingNo,ShipOutAPIJSON,Total_Weight From V_Packing_List_Main Where Shipout_Date > GETDATE()-10 and ShipOutAPIJSON is not null and Delete_TF is null and EN_Packing_List_Status = " + (int)DB.PackingListMain.EN.PackingListStatus.出貨中 + " and (ShippingNo='' or ShippingNo is null) and En_Ship_Method=" + (int)DB.OrderMain.EN.ShipMethod.新竹物流UNT; switch (Brands[CurrentBrandIdx]) { case "BE": sql += " AND EN_Pay_Method >= 7100 AND EN_Pay_Method < 7200 "; break; case "BM": sql += " AND EN_Pay_Method >= 7200 AND EN_Pay_Method < 7300 "; break; case "86": sql += " AND EN_Pay_Method >= 8600 AND EN_Pay_Method < 8700 AND (ShippingWarning is null or ShippingWarning not like N'%冷凍運輸%')"; break; case "86冷凍": sql += " AND EN_Pay_Method >= 8600 AND EN_Pay_Method < 8700 AND ShippingWarning like N'%冷凍運輸%'"; break; default: sql += " AND EN_Pay_Method < 7000 "; break; } if (ignoreOIds.Count > 0) { sql += " AND Order_Id not in (" + string.Join(",", ignoreOIds) + ") "; } DataTable dtPkList = UW.SQL.DTFromSQL(sql); if (dtPkList.Rows.Count == 0) { IsNoData = true; return; //context.Response.End(); } // 抓出 //DB.PackingListMain pm = new DB.PackingListMain(); //pm.Shipout_Date__Start = DateTime.Now.AddDays(-10); //pm.PackingListStatus = DB.PackingListMain.EN.PackingListStatus.出貨中; //pm.ShipMethod = DB.OrderMain.EN.ShipMethod.新竹物流UNT; //DataTable dtPkList = pm.GetQueryDT(AdditionalString: ""); List transDatas = new List(); List NotHandleOrderIds = new List(); foreach (DataRow row in dtPkList.Rows) { //有 shipping 就不取號了 if (!Convert.IsDBNull(row["ShippingNo"]) && row["ShippingNo"].ToString().Length > 0) { continue; } //檢查有無另一舊的 Packing 有號碼 if (IsExistsShippingNo(row)) { continue; } string json = row["ShipOutAPIJSON"].ToString(); LogisticsAPI.Logistics_Model.Ship ship = Newtonsoft.Json.JsonConvert.DeserializeObject(json); // 重量(kg) int totalWeight = Convert.ToInt32(Convert.ToDecimal(row["Total_Weight"]) / 1000); //20201209 取消限制 10 公斤 //if (totalWeight > 10) //{ // ignoreOIds.Add(row["Order_Id"].ToString()); // NotHandleOrderIds.Add(row["Order_Id"].ToString()); // continue; //} // 數量 (件數) //int allqty = (from x in ship.details where x.ptNo != "" select x.odQty).Sum(); int allqty = 1; // 是包裹數 int eqamt = 5; string mobile = ship.omReceMobile; if (string.IsNullOrEmpty(mobile)) { mobile = ship.omReceTel; } // sourceOrderNo = TW + Order_Id string str縣市區 = ship.omCityName.Replace("@", ""); if (str縣市區.StartsWith("新竹市") || str縣市區.StartsWith("嘉義市")) { str縣市區 = str縣市區.Substring(0, 3); } string str地址 = ship.omReceAddress; if (str縣市區.Length > 0) { str地址 = str地址.Replace("臺", "台").Replace(str縣市區, ""); } //代收款 DB.OrderMain om = new DB.OrderMain(Convert.ToInt32(row["Order_Id"])); int int代收 = 0; if (om.PayMethod == DB.OrderMain.EN.PayMethod.貨到付款_慶) { int代收 = om.Total_使用者最終要付的費用Int32; } //// 冷凍聯運費用 //if (om.ShippingWarning.Contains("冷凍運輸")) //{ // string restultOf聯運費用 = this.Get冷凍聯運(str縣市區 + str地址); // if (restultOf聯運費用.StartsWith("聯運費用")) // { // om.ShippingWarning = om.ShippingWarning + ";" + restultOf聯運費用; // } //} transDatas.Add(new LogisticsAPI.HctModel.TransData() { epino = ship.sourceOrderNo, ercsig = ship.omReceName, eraddr = ship.omAreaNo + " " + str縣市區 + str地址, ertel1 = mobile, ejamt = allqty.ToString(), eqamt = eqamt.ToString(), eqmny = int代收.ToString(), eprdcl2 = om.ShippingWarning.Contains("冷凍運輸") ? "003" : "001" }); } string HctResultJson = ""; string errMsg = ""; try { DealingCount++; HctService.Service1SoapClient hctService = new Service1SoapClient(); HctResultJson = hctService.TransData_Json(Companies[CurrentBrandIdx], Pwds[CurrentBrandIdx], Newtonsoft.Json.JsonConvert.SerializeObject(transDatas)); UW.WU.AppendLog("GetHctShippingData" + DateTime.Today.ToString("yyyyMMdd") + ".log", "HctResultJson: " + HctResultJson); } catch (Exception ex) { errMsg = ex.ToString(); UW.WU.AppendLog("GetHctShippingData" + DateTime.Today.ToString("yyyyMMdd") + ".log", errMsg); //throw; } if (errMsg != "") { SendNotifyMail("新竹物流API取得配編發生錯誤!", errMsg); context.Response.Write("error:" + errMsg); return; } List results = Newtonsoft.Json.JsonConvert.DeserializeObject>(HctResultJson); mailMsgs.Add("新竹物流配編結果:"); //{ "Num": "2", "success": "Y", "edelno": "1504735046", "epino": "UNT0202008200002", "erstno": "13 ", "eqamt": "10", "image": "89504E470D0A1A0A0000000D49484452000003E8000003E80103000000776D46A7000000017352474200AECE1CE90000000467414D410000B18F0BFC610500000006504C5445000000FFFFFFA5D99FDD000000097048597300000EC300000EC301C76FA8640000232F4944415478DAEDDDCF8F1BC77E20F0A269B87D10D47AD88B16984CD9F0027B1DE11DDE24265846DEC1C7FC0B7ED021971C46B7097630DD031A6E1F94E96B16583CFD0B39EE21889B6947BC04D13F10D84DF3A04B1017D7C0BAB42A55EDF7FBAD6EFE18CE70480EBB5B0F53F59EE41287C30FBBBB7E777515B36D06AFB715BCDE56F07A5BC1EB6D05AFB715BCDE56F07A5BC1EB6D05AFB715BCDE56F07A5BC1EB6D05AFB715BCDE56F07A5BC1E99A351D84D7BDEEF5B6F4AE6D36645EF7BAD71B0CEFA16E18EBB4A76319D86D4B2FA808E6EB7F318E6CD7AAC04A61336B3B65740FBAAB00D69F7BC3B866B6E8D82CB44C6816B9E8DD75B954FFDC10340B158B3266E300BE886282A27BD0B3525F7B24BA1FC85391175130D087A13CE314BDBB6EAABA77EDA9D736919ABF525138D422288C8BDE5D57B3AA3F5AFB9BC9D870ABCEF95845B3E8DD7539D3D7A7FAC1D88456F579A1A201E910DDA7BE3E11E5431B5ADDE3524639EA18DDA7BE3ECF0D72D0554F486949C7E8DDF56CDEE65BFB9B09E967A4179A53F4EE7A7CB5C5B9812E8FC47E74B3D0DEE59BEA50F0EC475F6CD3AF2D6F42D4A5265D4312C1E89D75B9A0AFABE70CE985D30DE8C53EF4E28A2EEC5BABEC2F104B47A496894173D4874E57471145EFAC6781EA6A97DEF188AC80B34AFA1BD4CD5C17A8E74E87B34ED13BEB31EA1D83E95D31CC7F19EA13F817EA5A54BA8A504FF42CBF27FBD059A0022524167419A464D0BB8BFA419513C0043D2CF5327A57DDB050066F2705167498E13396E3492858A452F836E6419513C6A81BEEF42A7A575DA36E53287230EFE10F47333D867F3FAFF41C752D663A45F7A1879A63FD2ADD49261D0EFB0DE9FF5A9DF9047515CD748ADE55578C17A114A8177898BFFC02FA341DE55675624A8AE52F8616929AB486EA77D029BA0F9D17E758C867A84F4B7D02FAC15378F3D4FD1E24F23172337DBC0F5D821E157AAE4F484F67FA58BBB70A2CDC722CF294088758F2E19F3BEB22B3A44731B62FE6FA9BF4E0B5D076A2A8C1057F43AB32B1965A95C519A7E85DF582C1018DE7FA9BD750DA4CD27062A7973DD0A35C930E0502546CF82E6C51C377A6E81EF45776882D4B4B6DABB739E91CF5E3D742F19116A5AEF12D11F526DC17B97B6F0232F68B453D665F746C7E89FAF3D3913061AA2A1D7A52982FB12765AAE8DDF5EFB0B5C09829F52F533BBA14A56E0F6FEDE0DD51B7D100F48ED30D1FA550B97E37B1BFA46F40FFFB9A757BE274ED7441BA457D0ABA629DB44EDDC4D100E4EE55DDA6D37F03FDE059AD3A246594FF8B223D6333FDEF2697F0E683673FD6A877DEFC83EDC235FFEF6A9EEA9C1EE7A0FF78F0CCD6A7CB8E649495FE7A551FFD51D851CD7AD181F65CDC19496A526B3E3BF317E9A1B0AF6AD55537433DEBA6A51E56BA0E42D0D39AF51872BA55222DA833A3834A97E1611FF45E9DBAEE625EC3FADBE9AAFBAAD21FF66BD7CD47A84770BD33EA46CA4FD3529F3EEF9D0BFBC70674285544A93FA9747B790AFA61CFE57715193E849E23BCA788E0D74D0097C642F402AB9C5934B08A57C606BAFD102B6EF865D223FBD39F87B3B24E19D25F557AE6F498C3D75598526DCC0D347ED93CDAB145606FEE8DAEF66550875FC6C605BCFAF2733E2F694D640ECE56741CB983F605E45270E08B486867CCA2F045CCCD4330ABFD3816503756B8A1936FFA737DAC23D35BD4236C469B3050676121A324C3688F174ACCA2321A0C0DEF6EAC5FE9C35EF605EAAFA1759742A3CA1C6B57CB2CE87CF0069AB44ABC901055E738805745E1D5A43051BEB1AE167438633FF44887AB67D36F58A44FF44938D305EAD8B2B521F46071FC209757A3D0D0B79BEB57C62E4C2F9AE997D0BBFAC3A2CE9D3E84E66CAEB995676228312AE6511E4AE8DA6FAC5F19B7317D4B3A90E90F1D6B7ED127BCD2FF997425A013910C70CCEC548C0B9BA05E4607E610BA5876BCB17E75CC4AA0FE0A7BEDA95D68AFA39E53E74D45F0E14102BA3C8DC663A797D1C41CC237DCE2D817939DBD39901ECCF4907445E4105ABD65B4D4F35DF4EE6D7A72AD5E7C15ED430F6ED3F36B752862F6A1F3DBF461A51B8EFAD8910A3E65BCA4279BEB9B8DCF933EAE744DFAD091F829C3257DF392B6BA2974CB3D31D265A5439106FAA03CF35FD92AEA74136EA16F745FE68A1EA19E38728CE77A49E75BE87A8313EF74755AEAD2A21EAA597E0F17752DB6D0CBF266FDCD48D2F571A98F5137BCD4E751A7AB681B5DCE0ABA35BA58D473D4294AE44214F59B87B2AEBD0F1BB3DB6ECA80AE796E1E977A823A1E64A9CFA3A88FB7D3B181B31EB754B39A8F4B3D445DDA993E8FA29E6FA9DF1E5CBDFEB1ABDF21C541521B5B57A9273874B658BF27FBD7B9023D76BA1B1FCFE77ABEA4877BD74D886794749E60250A591E8B3C79CE07F09F320AAF06E39BB3FBEE7A50404ACF5CAB121235B41F43EB9A92991255945A953767F7DDE75D40ED9F4397013E9A85050B258E32B96674C1CEAB28B5A815EBEE5D870E43A9C7D0E50B158E32B92E84FB22F3DE441D3A7496722B512F22D04D8024759FF43C4A3DA93AF4BD04AF7BDDCF68F57A1BFAAE697EB8E3EF655EF7BAD7BDEE75AF7BBD097DAC97C778741436AD67ACCB3A34668A7ADCB9373A4D33BABFBAFD9F387D6F8C33080BD649C6F743D7EC01E6B8F74587EBDEB45EB0A02D5DB4A753AA0B1775D6748EBB4637BC397DF25F4757741D36A35BA74359575DF726F59F21E2F4AAA4C554D7949EB6A9E39DF6259D91DE50AA2B1E40390F7A6897F4F5616F7A7680FA7110DA599A6F4E378CA60F2DE83B9675D12EBAC6D99CA2E82DEABB947572AE17373FF2748D2EB428A2D11DF5F95D5CBCA31E6EAA7F8AFAE4AEBA9CEB744B7B43DD8C49B7333D639D1DF478A6EB8551C15B75D7B25AD6D3AD539D9ADF3F77B79483AD74B6A8875BEBF15C77B7D33BDBEA6F9D0E616B1D135AA957539736D6F1BA83AE4A3D8AB6D6E3B9AE96868337D4E1BACB523F14DBEA245ED1F96EBA79C0F996B54C7C8D1E6EADBB5AE6F0906F57C33AF08ADEDD54C792960595AEC4C32DF5F83ABDB39B2EA30FC5567AE95DD1D946BAE9943ADEC8C55F2AECF3DE56ED3A79BD1E6DA8632D037AD9AA1C5AD5DBAA457D27BD5BA6BAB8D427569DDF3A98B4812E36D16D50EA59D7E9BF821EDC49EF143766F80D46CC8CB577D25D037157DDDE4D0F5D2D1BB6A363A4359D8A99EC861ABE769DD4A22D9D97AF35A8CBB9EE9E24BCA19AA9450FE6FA1BF7C14DEAD15C7FDBB81E5879A55CBF69C99A3AF46845B7CDE9816D538FDAD4719182153D6E4AB75EF7BAD737D4D98EA1E3F5757AD7EBEBF41AD37C9B3A6B590FEEAB6E1AEBC7BD7FBA6E55578D8D1E5CA7CB4DC76D6AD18B56F56CC311B37AF478C3B1CA5A74B3F1386D1DBADA788CDA0513ED53BF69D0E89ABBC00CDFAAB95DF370D596FA8DC3754DE83454CBB7D2C5BEF4B2BD24B6D1D5BE75BB99EE828AF6AB77B7D2E59EF5703BDDEE57175BE945B6D5B2CCB7EA762B7DBC5F3DDC4E1FEE570F5AD5B7BCEE177B4E75C1567AC7B653DA50A7D0EC5D17ADEAE116BAEED8EFF6AB77B7D04D07570FD8A7BE69CB0A9F18379FEA3DEB6C0BDD7E6AC2BDB52ED6E4F81BF4F11E757735F9363ADE8BDE9B2ED9C6BDC8521FEC51379BEBC3FDEB5BDC87CD9D3EDCA75E6C3C6A5487AE36BE2B54EAE37DEA7A637D60F8AFA017FBD4ED0DC5CDAA9E183E055DEE558FAFEFC05FABE304AFE95EF56C533D70BADDB72E36D14D58875E6CA8EB5A74B9A1AE789BBA1435E97C13BD880C2FF6AEAB0DF598D6D41EE3BA49CDEBD09A3534B54EB3368E1DA7D0E3E436C3A23DEA370C52AFE869ABFA0BB8F421EADBECAAB4377DA7E075AF7BFD7DD3797BBA7AFF75B663E8BCDFBA6C5B17EDE9C5FBAF5F3F7FFEF6451FF6D697D9B35E9A1BF722F7AB97299DB5A3BBE11A1C36B22DE82E3DEA967456CD60EFB4A2D3852FDAD2E9C2C7BBCFB3DA525F58421E3F18FF729BC5ECAEFF6A712BA537F420828E56D67C5DA7876E9C761B1D173FADF228EA92BAB432DA41679C9ECCDC62AE9182C47255C789E9A7F0377CBAD84A7761E3B946EECD4B3AADC560A53ADD59179BEA2E8586D5E32673BDB8831E6DAE87E5EFCDF49CF4B144FDECACCFB7D7EDA63A1DF715FD7FA13E946A57BD73173DF95AD8528772EBE1D5147CBBDEDD525FBAEEC987220AEDA0D8590F37D5CB3BE64B7AF8A0CF51A73550D883ED75BEA5BE74E61F3E38FA6D6803DC520EAE7B6F7B3DBA836E1E1F7CF28705BD176DA96FFAFC3B85ABA94EB303F6343441ECF4E3B38DF56C5DA25BA3CF02E9BDE36EA883812B698F4F37D6E5BACB7EB3AEDCF99FE94701E8C1D6BA5977D9AFD56947A165FDD1190B4255E9476A63DD9DFA9BFAC6D966BA3CEB06A1FC287435AC5CA75F09F439625B7DFE16CC7185FE5D77AE8FB7D06F7C1EF4269D76FD5CD6C7BA8F1B88E2C61990213FDD465F1736D487BAF724548975FA6FEBD797CABAC1BFF7FE47F8A6D23FFFDF35EAEEBA2FE9C9411F3756201D6AD863DBA81ED0AEB495DEAB5F0F71D38A523721E9DF60268433DF3BAA515FBDEEE6D1878B7AFF51A3BA66CDE9AB675EB9028374E85318D6A8AEBB23FBB375A9CECAA9ED34AB473FC8E4C7522F64ADFA356D5A487749EA746CDB5D34AA9BBFFDB7A35138D707CDEABFB93CCA9346F4AAC35B2D6D42F97DAEDB20B7B5EB66D61C43FDE8EBA39F4BDD04499DA9EE5AFDFBA3377959CEE3CFEAD32D5DF7255D1F7F7FA47E5F9E791C8C886AD697AEBB3EFEF793992EBBFAB168565727EA6979DD19533D5E9B4EADD0AE5C6AD39EAA1336A9725C7C741E36A9AB5325D9CF4E9781FCEAEA9E6C35EB7F6B70473CA77333B5696DFAD580E57C34FFD91B5CC0E3C746F55B82D7FFB475D674F0BAD7B749F37A1F1BF0675EF7BAD7B7D2132E43391EC551C2A6B93E863FDD113BB187228F4F8B504E46ECD9C41C3F9BE8CE283EB50FC584DED731C2EB5EF7BAD7BDEE75AF7BDDEB5EF7BAD7BDEE75AFDF55773F9DDD116B582FF065E5E6472DE9B35B7135EA8606110B374F6B49D70DE805E9E523F34BBAAA5F376E00B51C475DD265FD7A31D3790BBA7BB6A65A1F64492F9AD2353BA4DB814B7AD6940E092C6B51EFD8A27B558F1BD0BBA8CB2EFEFF8ACE1AD079A9D33E1D4B7AA77E7D68512F8255DD34A0FFE8749C5B7645D7DD064A5AD2B3F74E5741633A77F5E9A22EC3FBA1C7D7E8056F53CF44633AFCB9AAC7EDEA51A3BA58D6996D4A67ABBA6957EFB4A9C31B5AD455BB7AD0A62EC336F5A2413D5AD5799B3ABCBB453D6E578FDA4C75CCB6A89B5675DD6955EFB6A9E316848DEA4B6D1BF79063740FF4F87EEBA6459DB7AEDBB674E845AEF4A09BCBEFD7F5DF9BD53B6DEAAA3D1DC7ACBAEDE9D78D1636A6CB0E1E7E6B3AB3591B3AEE74D2B18A89D5F1F9C6747DDDBD89C67473DD7D997BA257BB40B5A4676E898E9674397B46AC51BD0CE5E2C0FEFEBBD7BDEE75AF7BDDEB5EF7BAD7BDEE75AF7BDDEB5EFF93D5EF16BCEE75AF7BFD4F51E786059616742C0C63511CD142FA26B0766075709BBECDB23CD7E81275F73C0FEAE7F81ED0F19EE2C03D0950A78EABFA056E643B233D241D1760EBDAAC6EFD036EB8754BEBC570264C3FA095D40B1999AE1DFC52B3FE90745A5A8F74EBF4B112A05FB730F35EF53EEA92D61D7C44FBE727A4E75AE8DFDBF056FDDA34BF79304E87A3348F708FD999CED5EF0D6F442FD034470BFAC0709537A48FD1D447B8C46FA9E39EAFF9B59B5FD6A4AB93657DDCAC2EB18029F72E007DD28CCE22D22525782C8DA1A0033DCFD5296F40E7A48F49C7B9528A45A027B9FA2A68400F499F483CEDAE9611A0A7B9FAA25BBB6E4D407AEE743CD98A831EE66A6541DF1A743B003D0B13E9BE8AEC42059D98439E2B3E6C40CF494F49B7094E5A415DE44A8C1BD34349093E2FF58326758B9B196106CFF155D4193B8EEE918E8B082FE8BD66CEBCABDFDD264C4EC75216FE34A10F2A5D96BA694E7F0799EC9C3BDDBEC38AE657C387D8C280B2BE765D9F07AE5529A19501FFB076AA38B42A41AFBDAC8BD919A4756A514BDA523AC4892B025BD4B9654103BA70BD09596D680D34F62672DC69B96E3D820FA29E94C414C7DC67624F2A778B19D4A96F1DBCEE75AFBB60848EDAD5716225C739F35E6F42376E43C4F2BAD33D8469933A9FE9AF7F065D44CDEB712766769418617AA239DDF417F581069D8F1BD4FB733D1F42D23B0C274DEAB49A91114AD8C9182E3E6F41D75C0A3BC68DE2C2246F50EFCDF5A93AB536CD474DEA11F5F943C9ADC4A1A7244F9AD7830274FD0CF449DAA07EECF4CF0A1CF085CC96FF1A36A9D398A6FCECFB103A82136C0BF306F5232ADBFFCF93EFFFCA6A01C97D6C9AD49F90FED39FFFEB97D02FC381BF6B4719EBD23FFD277CE9E5F1F3BF061D3B622A6A503FEA932E0E9E5AFB10075A4F9AD4FFA2872F5D92FE355C72FD896D50EFD3E6AF0FFBBD67EEA7A6D3A42E0E50FF63BF07A56C868F84761BD47BE231EA3FF4CE402FF0D5A041FD13F13146CDB13E8B68885B3779E6998849EF6BDA320C87B81BD43F1034964CAD4AFD10CE7A71D25C69A33F5AD0A5B8B0F6423757CBE8C3053D8BB2C8746B4CF42BFA7979DDB12FD3B13294EE064733BA317DB74C24E82A8057E00D056F4A870C7FC04B1DC7F703C8F24A34A71FF5835237F0DFD7BFC25F0DEA9F44CD8D60ACEA4FECA845FD73FB6B7B7AA3C1EB5EF77A93C1EB5EF77A9361457F376A53575FB6A9176EBD6BE8C048812DF909AD1F1640CF027E9A312B799DFAD0E912A8D0300E1D99A2833A4D4CCDCA85576AD3BB4E0712A7C686051DB0090C0B258B201A776BD475E052DDB0B0C140F783E2F7362F221D681E4C250EDF05C31A7509FA2B8B1357CE79AE6D32CEED2B05BA12C9AF0A74138E6BD4D597B8D5B9B5893AC33B22C9EB1C2727AA4445090D5D1A5EA7FE6E94D1923A89A2C941039CC0A0846C48B7A382F440F784C42162D0B59836A64B9AA31C3ABD3CF671537A194A3D213DCA132502A78775A6F96A499D657D94E807385C0FFFE876EDD55DC06BD17931D393048A3D5BE0E26271405384EBD6FBA887A84B1B269645BA83F3FF334EB3846BD253AB4A3D88F1818D1CC74B7902150ED6321D1AC419D6A6CF8E5D404473D4878627E601C7C5EC323B08CAE1DB9AF5F891C569791667E6255A50952BA3102F4554973E3BF3A238A189FF90C87454E677ABCE31BF2B5B973E3F769A1F887AA850C792067578ED5D13FA141F3E40543176629D7E86A580AD4D9F9F79B0F1A2C3096F49C7D9E058C136A697673EA10417A28E5C229BD769762E5EFC992E9BD10758C5B8A9D039E9D1E067CDBF939A1775EAE57DCF6161CE033719D935B478309122CD4CADAD4A5B44D8A8841635B5A103C9425C1735C1C6358B626867D7D9A2B6B1A57B13B26B701AEE4C871A169AF850BDC675F626A0EF42CF5A68E8C8D8051DBE13F4A8A0822B448D3A10B2C69B8FB7E9E286A7301BD1B5DD63B36D6BBDD9E075AF7BBDC9E075AF7BBDC9B0AAAFCC1C7EB1F3874FED6437DD08FBD6BD03BB143AC229012B0B17947B00AC7CE8E4AE3A742486E56C76F720F7801EA7CF18ED3BE0E6B4EB1E8366676736F351B9F99F4CCCF402DBDFAFB7D78DD0ACD4F161FA089F322BF57316B811437CD8F25ABD0816F5116D97D0D9468FD9575DD2717568CE18DE1498CEF4F2E01E902EE115768ACBA6A39E3A7D8AA33BD3C98426E4EEA2874B3AC767388835ECA3B24393A8899DC2013A1D578C102AB487A877E6FA6427DD2EEA433BD3E1184BFD7BC6C2E9345BD463D427B872BECD2CFC88D105BB29DCA4FFF2CBA47A86228584F37A54EAD0B799EBFF417A172E3C0EF0907E51EA9FC20118F60563FAFAA531D6EBE3E9A29E4F46EEE195522F53B5461D2EBC75C34B78DD13D08F59478EEFA44FC78BFA24475D953AFBA8D24F27E974DA192FE82FE0C7C7ACFB0BBCF6C8B0A793C996BA7B4E613A59D247953EC5445DA63A83BAECFC435EAEAC4169DEE9F0827964C794EAACD94277A3032A5FD4A7C975BA3E83330FF93DB8AA8339C6E53EC6857B0A426CAB439AC7875B59A0B074831CC7E67A95EAB0AC035D876E4C51D239C69291747D64B3BDEA8C2FA53A2CEB429BAEEAF1EF40572790E75C0E8D36D7E3DBF52AD551573BC5D50506D0EF2E75C31EC738D6A7A4CD227ADFCDA35C37E9865326E356D954455A8CD2993E2FEBBE412E8D331CDB806B3EC5AF33D3A5B4F127F4C6F116FAB7D18DBACB8E73FD25E8D3CB6EC19D3EC6048AFA04C5F14C1F6EA13F58ABC78F3BA65B9575FF897A8A83AAA11BCA4FF06A60E90FFA44DA8BCF28C70D36D7CD01BD12B3A70B3A630BFAFC97A1F8E3D30B614B9DAA124886AAC0FC9E4BDB71F93DD8423FE4B7E858E0BBAF60F0D82FE84C41C236F40C23EA12F544DADF90BE661C6845D7E226FD18AC49FA787A55CF58443AE60E31D753699E507E5FB3E6D8EA4869F95CE4EA755FD52FF1CCA7A00320A3E24BFB3CA4B2CEE2750F2B7DCD64E06BC669E95EDFFFFDB345FD3F3E5FD0E7A772AED36D9491BDC4D2861DBDC41C0725D1331AE32DA2CD75E9AA999F7EB3A87FFF19EA7842509F9DCA4B4AF323EDF4B7239BBE40FD49A5430190AEBD7BB73A4AEC0A879F1E53A5CA7F76FA9364419F9DCA87958E0B7661A30F4B1B6BE63AB56DBA5BE817EE5EDF3F3FA64A95E7A47FFD242D75CC7185DB13DFDAC3753A9C0DD24DB085DE75F7FABE39F812F4CF4BFDC1719AEA999E553A87FF4DFF0E74F89521EA0F4BFD770BBAE29BEBF04DE9C47EF36758A5779D6E1F7C1EA6FAB4D259A99BC78C75A717A8532D47AD2FD29F94BA3A136B07B5574689B94BD2973C257D043AB30782973ABEEB636A71E0532DA833D00B2A4E2BFD0F97952EA1E3B3EEC98395192FC2958C3FF070648BA0D4FFB18F3A6334ED011280D335EAB293E11A5698B750CF98D04F2F9F2816A04EDB5B865B1C7BE43EDAA0CE4488FA85D5A02BD4B1752F4ECB330FF90CDAFBE14CC71B87A43FAC74A0F547D010CF98DBA2E8361D6FB1FE483A1C76871627812FA3FB2255AA7C1E1D6F4D3A3D423D023DA7960618A8C77F79D82DF59831C5E3CDF52A40C93D8226132E4E92D251A652B93BB257F4D7F0BEF2CA166E5FBDF865BFFC9C69CC87902459B8AD4EFFB434CFA17C20F59DAA9AC6AA4A75961ED89CE9D215FF431B557DD8A17DBBF67EF52E23276AF68DEE1AFCA891D7BDDE64F0BAD7BDDE64F0BAD7BDDE64F0BAD7BDDE64F0BAD7B7DB77602FC1EB5EF7F9BDC1E075AF7BBDC9E0F505FDD568DAA29EB4AAA7ADEADF3216DE57FD71AB3A6FF5BAB7AA1BD1AA7EC4587B4FA8E97BAC2B9158DBA29EB6A84BB166F26DFD7ABF4DFDFFF5DAD4CD7198BE684F3F6A55FF246EF3CC3F6955FFBC555DA46D5EF796F576CF3CBBBF7A9FB779DDDBD57B226DB39689BE6D557FDE66AAB3CF456B7AB3C1EBEF8DFE7ADD13A4B5EBB94D5AD5472DEA139BB7A76BC627F7577FC4BAADE9380FFDBEEA86452D5EF7FBAC5B6BBDDE8ADE76AA3B6D71ACB25D1D77316A53BFCF695E78BD1DBDE7F57BA9B79CE63F69B555D9AADE6B556F6EC8C8FA9113EB75AF371ABCEE75FFDC447BF3E7BD7E3F759FDF9B0B5EF7FAFBA04F5AD5F356F5368F1D978C7273C8FF18B5A93F8870415F8E5BBE085BD3ADE19BF583453D1ABD6B44B76EB1AA4C1C88B96E703535DC4D6CACB94D32F601AF4B9F3ABDDFC7B5082D877F6961C291B486A31EA2DE0DEBD2C7AB7A64C3D118BEC45C4F6AD233D6417DD4636C414F4643F80FEA01ED2937AA47B7995B0A6DAE7FCB3E8C6C3E1AD04A96959ED7AC1F2FE93F8F5EC34541BD4BFAA426DDBA96DEE8F85C2CE8B49439E91DD2C735E9D9215574A3A3F332C7A553ED16409D92FE29E9D39A7426322C62479FACE863D28F489735E917EE93E7FA73F660498F6AD4D1C1BB81A3A36ACD76D2711DDE09E9C7A4AB9AF5DE0D7A4F34AB3F7BEEF4DCE99CF4A816DD967B128E7A70DDE36EDC75BA62FD52EFD7AA3376BA5617E1FDD0D3493A297533D3933A75AEAFEA98E617F4BC111DD23CE907EC61A50F6AD76767FE5A7DA8C5B8013D9BE97C6A2A3DC70D4B8B46F4EABAF3E90FBF2DD33CE9B281D26651BFFCACD48776A0850AEAD40DC5470BFA374E9FD802B79074BAAD49B7CBBA11D3979F51393FB6C579A8850E6AACDFAD9DB52A232CEB8CC83E401D123BD4F7A09B7A751774A9EB23F641007A0C2D2BCD44A94F9BD24FD867A4E382DB0CD7470E6A6C55CE745C981AAEBB3E89A621EA4B296DD2900ED15FDD63A28BB92CAF595F0D7A411F35AF2FDC9A4F1AD717B789091BD71748C39BD7F71FBCEEF57BAFBF1BB5A9AB2FDBD48B8C45EDE9C356F5AED375881B5FC751064DB9D04AA171DB0617AD51D7814B75B26BE3C0300E2444B3D0E914AD5197A0E326E805EE76EEC80C771F77D1C2EDBE519BAEBE740FC80D0B1B5EE87E009529448301362DCA688DFABB11ED9063731989B1A61DBA1269C3A1D37379CEF31A753B2A484FDC663DA807EA9C8F9D9EA8333EAE5597F4047AA284A53D6BB408412F50D722513D51AB5E86803669A22D6342DDE3D2E981EE0959A71E338AE3C66874EC2A0A9144BD8C36A4BBAD085BD5E55C97F5EBA9EBAFCD751B28D419DE9CC02450D4A92F1C3BED16246DE274417ABF311D374284137051908EFB02821EC475EA0B673EC0DDD2C6366378B17548BA705FAE2E7DE1D8CBAD088B0F29A9E1A001BC1A3F6A46A7EDF8707CEA80F4C4E9C5499DFAFCCCBBD20EAA345DEA033A230DE5B8AA9EB1FACCE909E9D33AF5F99977DBB281AE96F47133BA3BF070AE878DE950BFBBADC9E0FFD2F0B1D3134A8635EAE5C85482F7BB8DDBCACEE98169402F226C54DA8174D91DC748C626CCDFDA10A20369F7BA2CC2EA99771BC40E0B97DDA1B47B71014D49A54388C2ABE775B6690DB4E3B165557434EB48864D9C189BF68A716C6F740CABB33DAF0268D25BEC4DCCF510BA10CA6DC7D935ACCEBE0C342669CF4438D1A4C3C98F4115A643D72134FBAC64567B52D6ED1BD84CF023275EF77A93C1EB5E7F2FF5373B7EB4113ABABB5E3562CD7C5FD688FEF916A3D754F793BBEBF4586E8A0397D479B9C07B916916D2C6C0E663DAE7B9B09A9DAFDC1B9B3DC66D7AECB621DF9B667143C39A953AB5722F702FF34AD78F718FEBF0E206BD08F6A697FBADE3B1F34A5738E5D3BEF819F433E8D76BD4E8AF98557A8CFAD9D98EFAECCC97FA14F7B04F4729F5E270AF6E7CBDABCF4E412F70B682EC94FA21EA38D47107BD207349B7331D074F4AFD04753CC1F497D327B85C49485B65F33BEAE50C18545FA08ECBA00CE7FA17D0EC9FE0B918E25FD8D370FA3934843FDE5977A1D20DCD6B97ACD4BBDF59F7BA3E6367C2EDAD3FC0BF483F86EFFDC60677D1154D70BCAAFF8BD3536C7343BA0CE0D84F2377673ED1A5CE8EE9F1FDC4660F76BEEED7E8EF24CB40B723FBE34C677F73646FD2F5EEA94ED1EC86990E1DF85459C871A49B47382185F4F3CEAA3E9994FACEF99D7477570414D0A35445E9F74EC7A5D223BAEE2CEA96FAA0D2AD2A7575B083EEFAE774E617F4224AB5201D5E5727A50E5F157F6529D55915FFCEE97C87727E78936E7895E3A0EC0D5D3930C1F15B2A8BB332C719F638164E0F77D65DC0EB0ED73B31E27B91BAD28676769FEBC51177A54F811F01DDDD4A87777DB8C39977FABC9671FA4BD0FFBE330AA9ACCB2A5D3F8DA1CBADE6252D2ED7F198524EB89B1E5FAB5FF21414D0B307CCC6A05B134DAD7E9A434CCD6B990E8EF8A00E45A0FC6F3BE438A7276E9BF7991E92FED2E92CA2411DA8DFBFFA2BFB0AD24875EC36C3F7175DAC106DB14B7EFF36BA4EE721E86FBE77FAB774EC7C0C3ABDB9C05447671962A9925DCA063FEDA23FA0DFF89AB1C70B7A9FA7A84369337A7E3A4FF3FA2BACE328C75DD0ED6159E91079B94369630EE8154D35C44CEF8924B58F57F5A774F70E4EB3CBEFF813764CA7C3EEA61FBA7A6980CD8B997E1CE5A4A7D7EA38A817E05720FDE8A5A09CF39FB7DF405AD1B5205DE3E0E05C3FB263D4FF65AEBB5F783AB5A54EEF27FD09EA039A073ADD5657823E58D2836AE9E8ADD33FB132358FDF8C36D00DE990FF7669DBE0F8AC9DD7B0D2E94FEC9BD41C7740C7344F7A06DFEF465D87BBE9B2AC668CF8D1DACB4AFF1CBE09E8E98AFECC96A9CEE992F4DF410DB39B5EB8BE0BB4EB70D0D6E929A5407D8DFE15EA3F627277A90E923AE84F687686C1C70CB6D42FA8CE98E953CCBFA1D34FDFA4AE4D4BFA086F217CF104F491ACF23B87B2CEFCE1F2896BF5F66F1DD35D9D7342AD75D79E87827DAE87EA146A39B9AC332C6DA898A3BFB01DAC9FA20EA9C6888C6FA99B804A2EA767618EBAE2F08F220493A79017185751E6CEBCEA627ECF3AB6AC6131A5EAA70F2BBDE86CA92B773B82EA38C322FC606AD7D9824B28074355EADCE91C751AD4A68A0E0F36FECBC3AED38FB64E75D2E55557C3C2A7742B5D0AF86F8F6BA71782F4379672DC52885FF65D57D81C7595D8F2D8233BEFA60B3AAC6A06F33B6BFF71E1D34674C768551FDAA8ECC31E0BBB65398F0FDDFA11F22682D7BD7EBF75D674F0BAD7BDDE96DE56F07A5BC1EB6D05AFB715BCDE56F07A5BC1EB6D05AFB715BCDE56F07A5BC1EB6D05AFB715BCDE56F07A5BC1EB6D05AFB713ACFDFF5FA69FAFE65A388B0000000049454E44AE426082", "ErrMsg": "" } foreach (LogisticsAPI.HctModel.TransDataResult item in results) { if (item.success == "Y") { try { string orderid = item.epino.Replace("TW", ""); string shippingNo = item.edelno; //string erstno = item.erstno; string imageHex = item.image; //寫入DB sql = "Insert Into [Hct_Log] ([OrderId],[ShippingNo],[JsonResult],CompanyId) values (@OrderId,'@ShippingNo',N'@JsonResult','@CompanyId')"; UW.SQL.executeSQL(sql.Replace("@OrderId", orderid.Replace("'", "''")) .Replace("@ShippingNo", shippingNo.Replace("'", "''")) .Replace("@CompanyId", Companies[CurrentBrandIdx]) .Replace("@JsonResult", Newtonsoft.Json.JsonConvert.SerializeObject(item).Replace("'", "''"))); //把圖片轉成 image string fileName = orderid + "_" + shippingNo + ".jpg"; string savePath = SHOPUNT.DB.SysConfig.Path.LocalDataRoot() + "Hct\\" + fileName; byte[] byts = GetBytes(imageHex); Bitmap bmp = GetImage(byts); //20230629 新竹物流要求放大一下 1000 -> 1130 Bitmap newBmp = new Bitmap(1130, 1130); using (Graphics g = Graphics.FromImage(newBmp)) { g.DrawImage(bmp, 0, 0, 1130, 1130); } ImageCodecInfo jpgEncoder = GetEncoder(ImageFormat.Jpeg); System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality; EncoderParameters myEncoderParameters = new EncoderParameters(1); EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, 80L);//品質0到100分的中間值50分 myEncoderParameters.Param[0] = myEncoderParameter; //newBmp.Save(savePath, ImageFormat.Bmp); newBmp.Save(savePath, jpgEncoder, myEncoderParameters); bmp.Dispose(); newBmp.Dispose(); UW.SQL.executeSQL("Update Packing_List_Main Set ShippingNo='@ShippingNo', ShippingNo2='@fname' where Order_Id=@OrderId and Delete_TF is null" .Replace("@OrderId", orderid).Replace("@ShippingNo", shippingNo).Replace("@fname", fileName)); UW.SQL.executeSQL("Update Hct_Log Set Is_MakeImage='Y' where OrderId=@OrderId and ShippingNo='@ShippingNo'" .Replace("@OrderId", orderid).Replace("@ShippingNo", shippingNo)); mailMsgs.Add(item.epino + " 成功. -> " + shippingNo); } catch (Exception ex) { mailMsgs.Add(item.epino + " 失敗 -> " + ex.Message); UW.WU.AppendLog("GetHctShippingData" + DateTime.Today.ToString("yyyyMMdd") + ".log", item.epino + ";" + item.edelno + "轉圖檔失敗:" + ex.ToString()); } } else if (item.epino != null) { ignoreOIds.Add(item.epino.Replace("TW", "")); mailMsgs.Add(item.epino + " 失敗 -> " + item.ErrMsg); } else { var odList = transDatas.Select(x => x.epino.Replace("TW", "")).ToList(); ignoreOIds.AddRange(odList); mailMsgs.Add(string.Join(",", odList) + " 失敗 -> " + item.ErrMsg); } } if (NotHandleOrderIds.Count > 0) { mailMsgs.Add("\r\n有以下訂單因重量過大未處理:" + string.Join(",", NotHandleOrderIds)); } } /// /// 檢查是否已經取過號(可能刪出貨單重出) /// /// /// private bool IsExistsShippingNo(DataRow row) { string OrderId = row["Order_Id"].ToString(); string PackingListId = row["Id"].ToString(); string sql = @"Select ShippingNo,ShippingNo2 From Packing_List_Main (nolock) where Order_Id=@OrderId and Id<@PackingListId AND ShippingNo <> '' and ShippingNo2 <> '' and EN_Ship_Method=" + (int)DB.OrderMain.EN.ShipMethod.新竹物流UNT; DataTable dt = UW.SQL.DTFromSQL(sql.Replace("@PackingListId", PackingListId).Replace("@OrderId", OrderId)); if (dt.Rows.Count == 0) { return false; } UW.SQL.executeSQL(@"Update Packing_List_Main Set ShippingNo='@ShippingNo', ShippingNo2='@fname' where Id=@PackingListId and Delete_TF is null" .Replace("@PackingListId", PackingListId).Replace("@ShippingNo", dt.Rows[0][0].ToString()).Replace("@fname", dt.Rows[0][1].ToString())); return true; } private void SendNotifyMail(string Subject, string MailContent) { if (HttpContext.Current.Request.Url.Host.ToLower() != "mars.shopunt.com") { return; } DB.SystemMessage sm = DB.SystemMessage.GetSystemMessagebyName("物流API回報通知信"); sm.SendMail(Subject, MailContent); //string notifyEmails = string.Join(";", sm.ReceiversToList()); //UW.Mail.SendMail(notifyEmails, sm.Sender, Subject, MailContent); } byte[] GetBytes(string HexString) { int byteLength = HexString.Length / 2; byte[] bytes = new byte[byteLength]; string hex; int j = 0; for (int i = 0; i < bytes.Length; i++) { hex = new String(new Char[] { HexString[j], HexString[j + 1] }); bytes[i] = HexToByte(hex); j = j + 2; } return bytes; } byte HexToByte(string hex) { if (hex.Length > 2 || hex.Length <= 0) throw new ArgumentException("hex must be 1 or 2 characters in length"); byte newByte = byte.Parse(hex, System.Globalization.NumberStyles.HexNumber); return newByte; } //byte轉成圖片 Bitmap GetImage(byte[] b) { //將 byte 讀進 MemoryStream MemoryStream ms = new MemoryStream(b); //轉回成圖片 Bitmap bmp = (Bitmap)Bitmap.FromStream(ms); BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format1bppIndexed); //畫完圖, 把圖轉為 1bit 索引色(黑白單色) bmp = new Bitmap(bmp.Width, bmp.Height, bmpData.Stride, PixelFormat.Format1bppIndexed, bmpData.Scan0); return bmp; } private string Get冷凍聯運(string Address) { /* http://is1fax.hct.com.tw/Webedi_Erstno/Addr_Compare.aspx?USER=帳號&GROUP=3&ADDR=桃園市復興區中正路20號 帳號:0XXXXX6 紅色框起來的有值,表示需要聯運費!! */ string result = ""; using (System.Net.WebClient wc = new System.Net.WebClient()) { System.Text.Encoding encBig5 = System.Text.Encoding.GetEncoding(950); string url = "http://is1fax.hct.com.tw/Webedi_Erstno/Addr_Compare.aspx?USER=0XXXXX6&GROUP=3&ADDR=" + HttpUtility.UrlEncode(Address, encBig5); wc.Encoding = encBig5; byte[] vs = wc.DownloadData(url); result = encBig5.GetString(vs); } if (result != "") { UW.WU.AppendLog("GetHctShippingData" + DateTime.Today.ToString("yyyyMMdd") + ".log", "冷凍物流 raw: " + result); string[] seps = new string[] { "
" }; string[] rs = result.Split(seps, options: StringSplitOptions.RemoveEmptyEntries); var rr = rs.AsParallel().Where(x => x.Contains(":")).Select(x => x.Trim()).ToList(); UW.WU.AppendLog("GetHctShippingData" + DateTime.Today.ToString("yyyyMMdd") + ".log", "冷凍物流 處理後: " + string.Join("\r\n", rr)); string q = rr.Find(x => x.StartsWith("聯運費用(百公斤):") && x != "聯運費用(百公斤):"); if (q != null) { result = q; } else { result = ""; } } return result; } private ImageCodecInfo GetEncoder(ImageFormat format) { ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders(); foreach (ImageCodecInfo codec in codecs) { if (codec.FormatID == format.Guid) { return codec; } } return null; } private string GetEncodedQuery(string query) { byte[] rgbKey = System.Text.Encoding.UTF8.GetBytes(DateTime.Today.AddDays(-259).ToString("yyyyMMdd")); byte[] rgbIV = System.Text.Encoding.UTF8.GetBytes("MXXXXXM"); byte[] inputByteArray = System.Text.Encoding.UTF8.GetBytes(query); DESCryptoServiceProvider des = new DESCryptoServiceProvider() { IV = rgbIV, Key = rgbKey }; MemoryStream ms = new MemoryStream(); CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write); cs.Write(inputByteArray, 0, inputByteArray.Length); cs.FlushFinalBlock(); // toBase64 return Convert.ToBase64String(ms.ToArray()); } private string DecodeResultXml(string encodedXml) { byte[] inputByteArray = Convert.FromBase64String(encodedXml); byte[] rgbKey = System.Text.Encoding.UTF8.GetBytes(DateTime.Today.AddDays(-259).ToString("yyyyMMdd")); byte[] rgbIV = System.Text.Encoding.UTF8.GetBytes("MXXXXXXM"); DESCryptoServiceProvider des = new DESCryptoServiceProvider() { IV = rgbIV, Key = rgbKey }; MemoryStream ms = new MemoryStream(); CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write); cs.Write(inputByteArray, 0, inputByteArray.Length); cs.FlushFinalBlock(); return System.Text.Encoding.UTF8.GetString(ms.ToArray()); } public bool IsReusable { get { return false; } } }