private static string getNotFoundLastEventMessage(HolderLocationDTO holderLocation, string holderNameStr)
        {
            string msg = $"Не нашел события *выхода* из территории";

            try {             // попытка найти любое последнее событие прохода
                var lastEvent = holderLocation.EventsInfo.First(evInf => evInf.EventCode == 105);
                msg += $"\nПоследнее событие прохода:\n " +
                       $"{lastEvent.EventTime?.ToString("T", CultureInfo.CreateSpecificCulture("ru-RU"))} | " +
                       $"{lastEvent.ObjectName ?? "\"Контрольная точка не задана\""} | " +
                       $"{((lastEvent.Direction ?? 0) == 0 ? "Вход" : "Выход")} | " +
                       $"с '{lastEvent.StartAreaName}' в '{lastEvent.TargetAreaName}'\n";
            } catch (Exception) { }

            return(msg);
        }
        private async Task processResult(string message)
        {
            try {
                //Console.WriteLine(message);

                CommandBase command = CommandBase.FromJson(message);

                string cmdType = command.Command;

                if (cmdType == RequestPushEvent.Name)
                {
                    await onPushEvent(EventDTO.FromObject(command.Params));
                }
                else if (cmdType == ResponseHolderLocation.Name)
                {
                    await onResponseWhereCoworker(HolderLocationDTO.FromObject(command.Params));
                }
            } catch (Exception e) {
                Console.WriteLine(e.ToString());
            }
        }
        private async Task onResponseWhereCoworker(HolderLocationDTO holderLocation)
        {
            Console.WriteLine(holderLocation.ToJson(true));

            if (holderLocation?.HolderInfo?.HolderName == null)
            {
                await sendResponse($"Не нашел событий с указанным сотрудником. " +
                                   $"Возможно его небыло {holderLocation?.TimePeriod?.EndTime?.Date.ToString("dd MMMM yyyy", CultureInfo.CreateSpecificCulture("ru-RU"))}");

                return;
            }


            string holderNameStr = $"{holderLocation.HolderInfo.HolderSurname ?? ""} {holderLocation.HolderInfo.HolderName ?? ""} {holderLocation.HolderInfo.HolderMiddlename ?? ""}";

            var queryType = holderLocation.QueryType;

            if (queryType == QueryType.Type.WhereNow)
            {
                var eventDTO = holderLocation?.EventsInfo?.FirstOrDefault(ev => ev.EventCode == 105);
                if (eventDTO != null)
                {
                    await sendResponse($"*Сотрудник* {holderNameStr}\n" +
                                       $"{eventDTO?.EventTime?.ToString("T", CultureInfo.CreateSpecificCulture("ru-RU"))} | " +
                                       $"{eventDTO?.ObjectName ?? "Контрольная точка не задана"} | " +
                                       $"{((eventDTO?.Direction ?? 0) == 0 ? "Вход" : "Выход")}");

                    return;
                }
            }

            if (queryType == QueryType.Type.Where)               // юзер хочет знать где был(а) сотрудник
            {
                await sendResponse($"*Сотрудник* {holderNameStr}\n" +
                                   $"{buildEventsInfo(holderLocation.EventsInfo)}");

                return;
            }

            //
            // юзер хочет узнать зашёл/вышел сотрудник
            //

            Debug.Assert(holderLocation.IsHolderIn.HasValue);             // should be always true here!

            // найдем событие входа/выхода на/из територию
            var    foundedEventInf    = findInOrOutEvent(holderLocation.EventsInfo);
            string eventObjNameInStr  = $"{foundedEventInf?[0]?.ObjectName ?? "\"Контрольная точка не задана\""}";
            string eventObjNameOutStr = $"{foundedEventInf?[0]?.ObjectName ?? "\"Контрольная точка не задана\""}";

            // юзер хочет узнать сколько по времени был(а) сотрудник
            if (queryType == QueryType.Type.HowLong)
            {
                if (foundedEventInf?[0] != null)
                {
                    var inEventTime  = foundedEventInf[0]?.EventTime;
                    var outEventTime = foundedEventInf[1]?.EventTime;

                    if (!outEventTime.HasValue)       // последнее событие не выход на Улицу
                    {
                        try {                         // попытка найти любое последнее событие прохода
                            outEventTime = holderLocation.EventsInfo.First(evInf => evInf.EventCode == 105).EventTime;
                        } catch (Exception) { }
                    }

                    await sendResponse($"Время на территории: *{(outEventTime - inEventTime)?.ToString(@"%h'ч. '%m'мин.'")}*");
                }
                else
                {
                    await sendResponse($"Сотрудника \n" +
                                       $"{holderNameStr}\n" +
                                       $"*не было*");
                }

                return;
            }

            string eventInTimeStr  = $"{foundedEventInf?[0]?.EventTime?.ToString("T", CultureInfo.CreateSpecificCulture("ru-RU"))}";
            string eventOutTimeStr = $"{foundedEventInf?[1]?.EventTime?.ToString("T", CultureInfo.CreateSpecificCulture("ru-RU"))}";

            // зашёл?
            if (holderLocation.IsHolderIn.Value)
            {
                if (queryType == QueryType.Type.Empty)                   // юзер хочет ответ (Да, зашёл)/(Нет, не зашёл)
                {
                    if (foundedEventInf?[0] != null)
                    {
                        await sendResponse($"Да, {holderNameStr}\n" +
                                           $"*зашёл* в {eventInTimeStr} через {eventObjNameInStr}\n" +
                                           ((eventOutTimeStr == "") ? getNotFoundLastEventMessage(holderLocation, holderNameStr) :
                                            $"*вышел* в {eventOutTimeStr} через {eventOutTimeStr}\n"));
                    }
                    else
                    {
                        await sendResponse($"Нет, {holderNameStr}\n" +
                                           $"*не было*");
                    }
                }
                else                     // юзер хочет узнать (Во сколько)/(когда)/(в котором часу) сотрудник зашёл
                {
                    if (foundedEventInf?[0] != null)
                    {
                        await sendResponse($"{holderNameStr}\n" +
                                           $"{eventInTimeStr} | {eventObjNameInStr}\n");
                    }
                    else
                    {
                        await sendResponse($"Сотрудника \n{holderNameStr}\n" +
                                           $"*не было*");
                    }
                }
            }
            else                 // вышел?

            {
                if (foundedEventInf?[1] == null)
                {
                    await sendResponse(getNotFoundLastEventMessage(holderLocation, holderNameStr));
                }
                else
                {
                    if (queryType == QueryType.Type.Empty)
                    {
                        await sendResponse($"Да, {holderNameStr}\n" +
                                           $"*вышел* в {eventOutTimeStr} через {eventObjNameOutStr}\n");
                    }
                    else                         // юзер хочет узнать Во сколько/когда сотрудник вышел
                    {
                        await sendResponse($"{holderNameStr}\n" +
                                           $"{eventOutTimeStr} | {eventObjNameOutStr}");
                    }
                }
            }
        }
        private async Task processResult(string message)
        {
            if (CS_EventsNotifierSlackBot.Global.GlobalScope.CSEventsListeners.Count > 1)
            {
                return;
            }

            await Task.Delay(1000);

            try {
                Console.WriteLine("Emulator received: " + message);

                CommandBase command = CommandBase.FromJson(message);

                string cmdType = command.Command;

                if (cmdType == RequestHolderLocation.Name)
                {
                    HolderLocationPeriodDTO locationPeriod = HolderLocationPeriodDTO.FromObject(command.Params);

                    string keyToFindLast = locationPeriod.HolderName.Trim().ToLower()
                                           + locationPeriod.HolderMiddlename.Trim().ToLower()
                                           + locationPeriod.HolderSurname.Trim().ToLower()
                                           + locationPeriod.TimePeriod.EndTime?.Date;

                    List <EventInfoDTO> eventsInfo;
                    if (lastGeneratedEvents.ContainsKey(keyToFindLast))
                    {
                        lastGeneratedEvents.TryGetValue(keyToFindLast, out eventsInfo);
                        eventsInfo = eventsInfo.Where(ev => ev.EventTime >= locationPeriod.TimePeriod.StartTime && ev.EventTime <= locationPeriod.TimePeriod.EndTime).ToList();
                    }
                    else
                    {
                        eventsInfo = generateEvents(locationPeriod.TimePeriod);
                        lastGeneratedEvents.Add(keyToFindLast, eventsInfo);
                    }


                    // Emulatig Response from Database
                    var holderLocationDTO = new HolderLocationDTO()
                    {
                        QueryType  = locationPeriod.QueryType,
                        IsHolderIn = locationPeriod.IsHolderIn,
                        TimePeriod = locationPeriod.TimePeriod,
                        HolderInfo = new EventDTO()
                        {
                            CardNumber       = 421449585,
                            HolderType       = "\u041F\u043E\u0441\u0435\u0442\u0438\u0442\u0435\u043B\u044C",                       //Посетитель
                            HolderName       = locationPeriod.HolderName,
                            HolderMiddlename = locationPeriod.HolderMiddlename,
                            HolderSurname    = locationPeriod.HolderSurname,
                            HolderDepartment = "\u041E\u0442\u0434\u0435\u043B \u043A\u0430\u0434\u0440\u043E\u0432", //Отдел кадров
                            HolderTabNumber  = "\u0422\u0430\u0431\u0435\u043B\u044C 845"                             //Табель 845
                        },
                        EventsInfo = eventsInfo
                    };

                    var response = new ResponseHolderLocation(holderLocationDTO);

                    byte[] buffer = Encoding.UTF8.GetBytes(response.ToJson());
                    await webSocket.SendAsync(new ArraySegment <byte>(buffer), WebSocketMessageType.Text, true, token);
                }
            } catch (Exception e) {
                Console.WriteLine(e.ToString());
            }
        }