TmidController.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. using Azure.Cosmos;
  2. using Microsoft.AspNetCore.Mvc;
  3. using Microsoft.Azure.Cosmos.Table;
  4. using Microsoft.Extensions.Configuration;
  5. using Microsoft.Extensions.Options;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Linq;
  9. using System.Text.Json;
  10. using System.Threading.Tasks;
  11. using TEAMModelOS.Models;
  12. using TEAMModelOS.SDK.DI;
  13. using TEAMModelOS.SDK.Extension;
  14. using TEAMModelOS.SDK.Models;
  15. using TEAMModelOS.SDK.Services;
  16. namespace TEAMModelBI.Controllers.BITmid
  17. {
  18. [Route("tmid")]
  19. [ApiController]
  20. public class TmidController : ControllerBase
  21. {
  22. private readonly AzureCosmosFactory _azureCosmos;
  23. private readonly AzureStorageFactory _azureStorage;
  24. private readonly AzureRedisFactory _azureRedis;
  25. private readonly DingDing _dingDing;
  26. private readonly Option _option;
  27. private readonly IConfiguration _configuration;
  28. private readonly HttpTrigger _httpTrigger;
  29. public TmidController(AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage, AzureRedisFactory azureRedis, DingDing dingDing, IOptionsSnapshot<Option> option, IConfiguration configuration, HttpTrigger httpTrigger)
  30. {
  31. _azureCosmos = azureCosmos;
  32. _azureStorage = azureStorage;
  33. _azureRedis = azureRedis;
  34. _dingDing = dingDing;
  35. _option = option?.Value;
  36. _configuration = configuration;
  37. _httpTrigger = httpTrigger;
  38. }
  39. /// <summary>
  40. /// 取得TMID綜合資料
  41. /// </summary>
  42. /// <param name="jsonElement"></param>
  43. /// <returns></returns>
  44. [ProducesDefaultResponseType]
  45. //[AuthToken(Roles = "admin")]
  46. [HttpPost("get-tmidstics")]
  47. public async Task<IActionResult> GetTmidStics(JsonElement jsonElement)
  48. {
  49. try
  50. {
  51. if (!jsonElement.TryGetProperty("tmids", out JsonElement tmidsJobj)) return BadRequest();//TMID(array)
  52. var tmids = tmidsJobj.Deserialize<List<string>>();
  53. if (tmids.Count is 0) return BadRequest();
  54. //服務Client端
  55. var cosmosClientIes5 = _azureCosmos.GetCosmosClient(); //CosmosDB IES5
  56. var cosmosClientCsv2 = _azureCosmos.GetCosmosClient(name: "CoreServiceV2"); //CosmosDB CSV2
  57. var storageClientCsv2 = _azureStorage.GetCloudTableClient(name: "CoreServiceV2"); //Storage CSV2
  58. var tableCouponClient = storageClientCsv2.GetTableReference("Coupon");
  59. var tablePointsClient = storageClientCsv2.GetTableReference("Points");
  60. var redisClient = _azureRedis.GetRedisClient(4);
  61. //存放user資料
  62. Dictionary<string, TmidStics> tmidDic = new();
  63. QueryDefinition query =
  64. new QueryDefinition(@"SELECT c.id, c.name, c.mobile, c.mail FROM c WHERE (ARRAY_CONTAINS(@key, c.id) OR ARRAY_CONTAINS(@key, c.mobile))")
  65. .WithParameter("@key", tmids);
  66. await foreach (var item in cosmosClientCsv2
  67. .GetContainer("Core", "ID2")
  68. .GetItemQueryStreamIterator(query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("base") }))
  69. {
  70. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  71. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  72. {
  73. foreach (var doc in json.RootElement.GetProperty("Documents").EnumerateArray())
  74. {
  75. string id = doc.GetProperty("id").GetString();
  76. if(!tmids.Contains(id)) tmids.Add(id);
  77. //基本資料
  78. TmidStics tmidStics = (tmidDic.ContainsKey(id)) ? tmidDic[id] : new() { id = id };
  79. string tmidName = doc.GetProperty("name").GetString();
  80. string tmidMobile = GenDataMask(doc.GetProperty("mobile").GetString(), "mobile");
  81. string tmidMail = GenDataMask(doc.GetProperty("mail").GetString(), "mail");
  82. //票券
  83. var usersCoupons = tableCouponClient.Get<DynamicTableEntity>(id);
  84. foreach (var coupon in usersCoupons)
  85. {
  86. tmidStics.coupons.Add(
  87. new TmidCoupon()
  88. {
  89. code = coupon.RowKey,
  90. exchange = coupon.Properties["exchangeTime"].DateTimeOffsetValue.Value.ToUnixTimeSeconds(),
  91. });
  92. }
  93. //登入各服務的時間
  94. var loginTime = await redisClient.HashGetAllAsync(id);
  95. foreach (var t in loginTime)
  96. {
  97. if (!t.Name.StartsWith("HiTeach") && !_dicClientIds.ContainsKey(t.Name)) continue;
  98. tmidStics.login.Add(
  99. new TmidLoginTime()
  100. {
  101. product = t.Name.StartsWith("HiTeach") ? t.Name.ToString().Split("-")[0] : _dicClientIds[t.Name],
  102. time = (long)t.Value
  103. });
  104. }
  105. //積分
  106. var usersPoints = tablePointsClient.Get("Points", id);
  107. tmidStics.points.points = (usersPoints != null) ? usersPoints.Properties["Points"].Int32Value.Value : 0;
  108. tmidStics.points.level = (usersPoints != null) ? usersPoints.Properties["Level"].Int32Value.Value : 0;
  109. tmidStics.points.balance = (usersPoints != null) ? usersPoints.Properties["Balance"].Int32Value.Value : 0;
  110. //個人服務授權
  111. tmidStics.prod = await getTMIDAuthService(cosmosClientCsv2, id, "", true);
  112. tmidDic.Add(id, tmidStics);
  113. }
  114. }
  115. }
  116. //ID進階資料
  117. QueryDefinition queryex = new QueryDefinition(@"SELECT c.id, c.name, c.mobile, c.mail, c.country, c.province, c.city, c.schoolCode, c.schoolCodeW FROM c WHERE (ARRAY_CONTAINS(@key, c.id) OR ARRAY_CONTAINS(@key, c.mobile))")
  118. .WithParameter("@key", tmids);
  119. await foreach (var item in cosmosClientCsv2
  120. .GetContainer("Core", "ID2")
  121. .GetItemQueryStreamIterator(queryex, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("base-ex") }))
  122. {
  123. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  124. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  125. {
  126. foreach (var doc in json.RootElement.GetProperty("Documents").EnumerateArray())
  127. {
  128. string id = doc.GetProperty("id").GetString();
  129. TmidStics tmidStics = (tmidDic.ContainsKey(id)) ? tmidDic[id] : new() { id = id };
  130. if (string.IsNullOrWhiteSpace(tmidStics.name)) tmidStics.name = doc.GetProperty("name").GetString();
  131. if (string.IsNullOrWhiteSpace(tmidStics.mobile)) tmidStics.mobile = GenDataMask(doc.GetProperty("mobile").GetString(), "mobile");
  132. if (string.IsNullOrWhiteSpace(tmidStics.mail)) tmidStics.mail = GenDataMask(doc.GetProperty("mail").GetString(), "mail");
  133. tmidStics.country = doc.GetProperty("country").GetString();
  134. tmidStics.province = doc.GetProperty("province").GetString();
  135. tmidStics.city = doc.GetProperty("city").GetString();
  136. tmidStics.schoolCode = (doc.TryGetProperty("schoolCode", out JsonElement schCode)) ? schCode.GetString() : string.Empty;
  137. tmidStics.schoolCodeW = (doc.TryGetProperty("schoolCodeW", out JsonElement schCodeW)) ? schCodeW.GetString() : string.Empty;
  138. }
  139. }
  140. }
  141. //蘇格拉底資料
  142. query = new QueryDefinition(@"SELECT * FROM c WHERE (ARRAY_CONTAINS(@key, c.id))")
  143. .WithParameter("@key", tmidDic.Keys.ToList());
  144. await foreach (var item in cosmosClientCsv2
  145. .GetContainer("Core", "ID2")
  146. .GetItemQueryStreamIterator(query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("sokrates") }))
  147. {
  148. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  149. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  150. {
  151. foreach (var doc in json.RootElement.GetProperty("Documents").EnumerateArray())
  152. {
  153. string id = doc.GetProperty("id").GetString();
  154. if (doc.TryGetProperty("hiteach_data", out var elementHiteachData))
  155. {
  156. if (elementHiteachData.TryGetProperty("total", out var elementTotal))
  157. {
  158. if (elementTotal.TryGetProperty("t_data", out var tDataValue)) tmidDic[id].sokrates.t_data = tDataValue.GetString();
  159. if (elementTotal.TryGetProperty("t_green", out var tGreenValue)) tmidDic[id].sokrates.t_green = tGreenValue.GetString();
  160. if (elementTotal.TryGetProperty("duration", out var durationValue)) tmidDic[id].sokrates.duration = durationValue.GetString();
  161. if (elementTotal.TryGetProperty("attendance", out var attendanceValue)) tmidDic[id].sokrates.attendance = attendanceValue.GetString();
  162. if (elementTotal.TryGetProperty("interaction", out var interactionValue)) tmidDic[id].sokrates.interaction = interactionValue.GetString();
  163. if (elementTotal.TryGetProperty("learning_duration", out var learningDurationValue)) tmidDic[id].sokrates.learning_duration = learningDurationValue.GetString();
  164. }
  165. }
  166. }
  167. }
  168. }
  169. //IES5
  170. ///個人空間使用狀況
  171. foreach (KeyValuePair<string, TmidStics> dicItem in tmidDic)
  172. {
  173. string tmidNow = dicItem.Key;
  174. var (usedSize, teach, total, surplus, catalog) = await BlobService.GetSurplusSpace(tmidNow, "private", _option.Location, _azureCosmos, _azureRedis, _azureStorage, _dingDing, _httpTrigger);
  175. tmidDic[tmidNow].ies5.usedSize = usedSize;
  176. tmidDic[tmidNow].ies5.teachSize = teach * 1073741824;
  177. tmidDic[tmidNow].ies5.totalSize = total * 1073741824;
  178. tmidDic[tmidNow].ies5.surplusSize = surplus;
  179. }
  180. //輸出
  181. List<object> data = new();
  182. foreach (KeyValuePair<string, TmidStics> dicItem in tmidDic)
  183. {
  184. data.Add(dicItem.Value);
  185. }
  186. return Ok(new { data });
  187. }
  188. catch (Exception ex)
  189. {
  190. //await _dingDing.SendBotMsg($"BI,{_option.Location} /tmid/get-tmidstics \n {ex.Message}\n{ex.StackTrace}", GroupNames.台北開發測試群組);
  191. return BadRequest();
  192. }
  193. }
  194. //取得TMID服務授權週期
  195. public async Task<List<object>> getTMIDAuthService(CosmosClient cosmosClientCsv2, string tmid, string prodCode, bool validFlg)
  196. {
  197. long now = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
  198. var qryOption = new QueryRequestOptions() { PartitionKey = new PartitionKey("servicePeriod") };
  199. string whereSql = $"c.saleClient.tmid = '{tmid}'";
  200. if (!string.IsNullOrWhiteSpace(prodCode)) whereSql += $" AND c.prodCode = '{prodCode}'";
  201. if (validFlg) whereSql += $" AND c.startDate <= {now} AND {now} <= c.endDate";
  202. string sql = $"SELECT c.id, c.prodCode, c.type, c.startDate, c.endDate, c.number, c.unit, c.aprule FROM c WHERE {whereSql}";
  203. var client = cosmosClientCsv2.GetContainer("Habb", "Auth");
  204. var result = new List<object>();
  205. await foreach (var item in client.GetItemQueryStreamIterator(queryText: sql, requestOptions: qryOption))
  206. {
  207. var json = await JsonDocument.ParseAsync(item.ContentStream);
  208. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  209. {
  210. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  211. {
  212. result.Add(
  213. new
  214. {
  215. id = obj.GetProperty("id").GetString(),
  216. prodCode = obj.GetProperty("prodCode").GetString(),
  217. type = obj.GetProperty("type").GetInt32(),
  218. startDate = obj.GetProperty("startDate").GetInt64(),
  219. endDate = obj.GetProperty("endDate").GetInt64(),
  220. number = obj.GetProperty("number").GetInt32(),
  221. aprule = obj.GetProperty("aprule")
  222. });
  223. }
  224. }
  225. }
  226. return result;
  227. }
  228. //取得TMID購買紀錄
  229. public async Task<List<Ies5OrderHis>> getTMIDAuthOrder(CosmosClient cosmosClientCsv2, string tmid, string prodCode)
  230. {
  231. SortedDictionary<string, Ies5OrderHis> OrderDic = new SortedDictionary<string, Ies5OrderHis>();
  232. var qryOption = new QueryRequestOptions() { PartitionKey = new PartitionKey("order") };
  233. //服務 ※序號、硬體 不列入購買紀錄
  234. string strQueryV = $"SELECT * FROM c WHERE IS_DEFINED(c.saleClient.tmid) AND c.saleClient.tmid = '{tmid}' AND c.prodType = 'service'";
  235. if (!string.IsNullOrWhiteSpace(prodCode))
  236. {
  237. strQueryV += $" AND c.prodCode = '{prodCode}'";
  238. }
  239. await foreach (OrderHisService orderService in cosmosClientCsv2.GetContainer("Habb", "Auth").GetItemQueryIterator<OrderHisService>(strQueryV, null, qryOption))
  240. {
  241. Ies5OrderHisService ies5OrderVRow = new Ies5OrderHisService();
  242. ies5OrderVRow.prodCode = orderService.prodCode;
  243. ies5OrderVRow.type = (orderService.contract.Equals(1)) ? "C" : (orderService.contract.Equals(2)) ? "G" : "N"; //授權方式 [FROM]contract契約型態 0:新約 1:續約 2:變更 [TO]type N:新約 C:續約 G:變更
  244. ies5OrderVRow.sdate = orderService.startDate;
  245. ies5OrderVRow.edate = orderService.endDate;
  246. ies5OrderVRow.number = orderService.number;
  247. ies5OrderVRow.unit = orderService.unit;
  248. //加入Order字典
  249. string OrderID = orderService.orderinfo.orderid.ToString();
  250. long OrderDate = orderService.orderinfo.createDate;
  251. if (OrderDic.ContainsKey(OrderID))
  252. {
  253. OrderDic[OrderID].service.Add(ies5OrderVRow);
  254. }
  255. else
  256. {
  257. Ies5OrderHis ies5OrderHisNew = new Ies5OrderHis();
  258. ies5OrderHisNew.id = OrderID;
  259. ies5OrderHisNew.date = OrderDate;
  260. ies5OrderHisNew.service.Add(ies5OrderVRow);
  261. OrderDic.Add(OrderID, ies5OrderHisNew);
  262. }
  263. }
  264. //輸出項
  265. List<Ies5OrderHis> Result = new List<Ies5OrderHis>();
  266. foreach (KeyValuePair<string, Ies5OrderHis> item in OrderDic)
  267. {
  268. Result.Add(item.Value);
  269. }
  270. return Result;
  271. }
  272. //Tool
  273. //資料遮罩
  274. ///規則:
  275. ///1.手機、電話:隱藏後4碼
  276. ///2.Mail:隱藏@前資料
  277. ///3.姓名:只顯示第一個字元
  278. ///4.身分證、護照:隱藏後4碼
  279. public string GenDataMask(string data, string type)
  280. {
  281. int length = 0;
  282. string subString = string.Empty;
  283. if (!string.IsNullOrWhiteSpace(data))
  284. {
  285. switch (type)
  286. {
  287. case "mobile":
  288. case "id":
  289. length = 4;
  290. subString = data.Substring(data.Length - length, length);
  291. data = data.Replace(subString, "****");
  292. break;
  293. case "mail":
  294. string[] dataList = data.Split("@");
  295. subString = dataList.First();
  296. data = data.Replace(subString, "****");
  297. break;
  298. case "name":
  299. length = 2;
  300. subString = data.Substring(data.Length - length, length);
  301. data = data.Replace(subString, "〇〇");
  302. break;
  303. }
  304. }
  305. return data;
  306. }
  307. //Model
  308. //TMID統計 基本資訊
  309. private class TmidStics
  310. {
  311. public string id { get; set; }
  312. public string name { get; set; }
  313. public string mobile { get; set; }
  314. public string mail { get; set; }
  315. public string country { get; set; }
  316. public string province { get; set; }
  317. public string city { get; set; }
  318. public string schoolCode { get; set; }
  319. public string schoolCodeW { get; set; }
  320. public TmidSticsIes5 ies5 { get; set; } = new(); //IES統計資料
  321. public TmidPoints points { get; set; } = new();
  322. public TmidSokrates sokrates { get; set; } = new();
  323. public List<TmidCoupon> coupons { get; set; } = new();
  324. public List<TmidLoginTime> login { get; set; } = new();
  325. public List<object> prod { get; set; } = new();
  326. }
  327. //TMID統計 IES5資訊
  328. private class TmidSticsIes5
  329. {
  330. public long usedSize { get; set; } //已使用的存儲空間(Byte)
  331. public long teachSize { get; set; } //分配給教師的空間(Byte)
  332. public long totalSize { get; set; } //總空間(Byte)
  333. public long surplusSize { get; set; } //剩余的空間(Byte)
  334. }
  335. private class TmidPoints
  336. {
  337. public int points { get; set; } = 0; //累積的點數(只加不減)
  338. public int balance { get; set; } = 0; //可用的點數
  339. public int level { get; set; } = 0; //等級
  340. }
  341. private class TmidCoupon
  342. {
  343. public string code { get; set; }
  344. public long exchange { get; set; }
  345. }
  346. private class TmidLoginTime
  347. {
  348. public string product { get; set; }
  349. public long time { get; set; }
  350. }
  351. private class TmidSokrates
  352. {
  353. public string t_data { get; set; }
  354. public string t_green { get; set; }
  355. public string duration { get; set; }
  356. public string attendance { get; set; }
  357. public string interaction { get; set; }
  358. public string learning_duration { get; set; }
  359. }
  360. //[API輸出] 訂單履歷
  361. public class Ies5OrderHis
  362. {
  363. public Ies5OrderHis()
  364. {
  365. service = new List<Ies5OrderHisService>();
  366. }
  367. public string id { get; set; }
  368. public long date { get; set; }
  369. public List<Ies5OrderHisService> service { get; set; } = new ();
  370. }
  371. //[API輸出] 訂單履歷.服務型產品
  372. public class Ies5OrderHisService
  373. {
  374. public string prodCode { get; set; } //產品代碼
  375. public string type { get; set; } //授權方式 N:新約 C:續約
  376. public long sdate { get; set; } //授權起始時間
  377. public long edate { get; set; } //授權終止時間
  378. public int number { get; set; } //購買數量
  379. public string unit { get; set; } //購買單位 無單位者為null
  380. }
  381. //[承接DB] DB: Habb.Auth
  382. //[承接DB] 訂單履歷基本Class
  383. public class OrderHisBase
  384. {
  385. public string id { get; set; } //OPID
  386. public OrderHisOrderInfo orderinfo { get; set; } //訂單資訊
  387. public string prodCode { get; set; } //產品代碼
  388. public SerialSaleClient saleClient { get; set; } = null; //銷售終端
  389. public string prodType { get; set; } //產品類型 serial:序號 service:服務 hard:硬體
  390. public string dataType { get; set; } //資料類型
  391. public long operationTime { get; set; } //最新資料變更時間戳記
  392. public int ttl { get; set; } = -1; //過期刪除秒數
  393. }
  394. //[承接DB] 訂單履歷基本Class.銷售終端
  395. public class SerialSaleClient
  396. {
  397. public string name { get; set; } //[String]銷售終端姓名
  398. public string schoolCode { get; set; } = null; //[String]銷售終端學校代碼
  399. public string clientId { get; set; } = null; //[String]銷售終端客戶ID
  400. public string tmid { get; set; } = null; //[String]TMID
  401. public string type { get; set; } //[String]銷售終端資料類型 school:學校 client:經銷商客戶
  402. public string countryId { get; set; } //[String]國家代碼
  403. public string provinceId { get; set; } //[String]省代碼
  404. public string cityId { get; set; } //[String]市代碼
  405. public string schoolShortCode { get; set; } //[String]學校簡碼
  406. public string districtId { get; set; } //[String]區代碼
  407. public string dataCenter { get; set; } //[String]數據中心
  408. }
  409. //[承接DB] 訂單履歷基本Class.訂單資訊
  410. public class OrderHisOrderInfo
  411. {
  412. public string orderid { get; set; } //[String]訂單編號
  413. public int orderAudit { get; set; } //[Int]訂單審核狀態 0:待審, 1:通過, 2:否決, 3:問題
  414. public int orderProperty { get; set; } //[Int]訂單類型 0:銷售,1:展示申請 2:內部申請
  415. public long createDate { get; set; } //訂單創建時間
  416. }
  417. //[承接DB] 訂單履歷 服務類
  418. public class OrderHisService : OrderHisBase
  419. {
  420. public int type { get; set; } //[Int]授權類型 0:銷售 1:試用
  421. public int contract { get; set; } //[Int]契約型態 0:新約 1:續約
  422. public long startDate { get; set; } //[long]授權起始日期 Timestamp(UTC)
  423. public long endDate { get; set; } //[long]授權終止日期 Timestamp(UTC)
  424. public int number { get; set; } //[Int]數量
  425. public string unit { get; set; } //[String]單位 (無者為空)
  426. }
  427. //雲端服務ClientId列表
  428. private readonly Dictionary<string, string> _dicClientIds = new()
  429. {
  430. { "917d02f2-5b91-404e-a71d-7bdd926ddd81", "HiTeach" },
  431. { "c5328340-b8eb-4489-8650-8c8862d7acfe", "HiTeach" },
  432. { "118d2d4d-32a3-44c0-808a-792ca73d3706", "HiTeachCC" },
  433. { "227082f4-8db0-4517-b281-93dba9428bc7", "HiTeachCC" },
  434. { "371a99aa-7efd-4c3a-90a8-95b7db4f42c0", "HiTA" },
  435. { "0ed38cde-e7fe-4fa6-9eaa-33ad404eb532", "HiTA" },
  436. { "531fecd1-b1a5-469a-93ca-7984e1d392f2", "IES5" },
  437. { "c7317f88-7cea-4e48-ac57-a16071f7b884", "IES5" },
  438. { "c8de822b-3fcf-4831-adba-cdd14653bf7f", "Account" },
  439. { "516148eb-6a38-4657-ba98-a3699061937f", "Account" },
  440. { "d7193896-9b12-4046-ad44-c991dd48cc39", "Sokrates" },
  441. { "59009e38-6e30-4116-814b-7605939edc47", "Sokrates" },
  442. { "626c7285-15aa-4abe-8c0d-2c5ff1381538", "SokAPP" },
  443. { "5bcc16a5-7d20-4cc4-b5c2-8ed0416f32b6", "SokAPP" },
  444. { "044482b5-d024-4f23-9b55-906884243405", "IRS" },
  445. { "5e27b7e3-b36c-4ce9-b838-e94fd0cea080", "IRS" }
  446. };
  447. }
  448. }