Beispiel #1
0
        async void openStateCheckingAsyncLoop()
        {
            await ThreadingUtils.ContinueAtDedicatedThread(CancellationToken.None);

            var period = new PeriodDelay(1000);

            while (true)
            {
                if (_openedDevice != null)
                {
                    try
                    {
                        var devices = getAllDevices();
                        var exists  = devices.FirstOrDefault(d => d.LocId == _openedDevice.LocId &&
                                                             d.SerialNumber == _openedDevice.SerialNumber &&
                                                             d.Description == _openedDevice.Description) != null;
                        if (!exists)
                        {
                            Close();
                        }
                    }
                    catch (Exception ex)
                    {
                        Logger.LogError(null, "Ошибка ", ex);
                    }
                }

                await period.WaitTimeLeftAsync();
            }
        }
Beispiel #2
0
        public async Task <StatusReadResult> TryReadStatusAsync(DeviceOperationScope scope, AsyncOperationInfo cancellation)
        {
            await ThreadingUtils.ContinueAtThreadPull(cancellation);

            using (Logger.Indent)
            {
                Logger.LogInfo(null, $"Чтение статуса прибора \"{Name}\"...");

                var result = await ReadAsync(Command.STATUS, scope, cancellation);

                if (result.Status == ReadStatus.OK)
                {
                    var flagsEntity     = result.Entities.ElementAt(0);
                    var numOfStatusBits = flagsEntity.Descriptor.Length.Length * 8;
                    var flags           = (uint)(dynamic)flagsEntity.Value;
                    var serial          = (ushort)result.Entities.ElementAt(1).Value;
                    var status          = new DeviceStatusInfo.StatusInfo(numOfStatusBits, flags);

                    Logger.LogInfo(null, $"Статус: {status.ToBinString()}");

                    return(new StatusReadResult(result, new DeviceStatusInfo(Id, serial, status)));
                }
                else
                {
                    return(new StatusReadResult(result, null));
                }
            }
        }
        async Task daemon()
        {
            await ThreadingUtils.ContinueAtDedicatedThread();

            while (true)
            {
                try
                {
                    using var scope = ScopeFactory.CreateScope();
                    using var db    = scope.ServiceProvider.GetRequiredService <TestsContext>();
                    var threshold = DateTime.UtcNow.AddDays(-3);
                    var legacy    = await db.Cases
                                    .Where(c => c.State == TestCaseState.RecordedButNotSaved && c.CreationDate < threshold)
                                    .ToArrayAsync();

                    foreach (var e in legacy)
                    {
                        e.IsDeleted = true;
                    }
                    await db.SaveChangesAsync();

                    Logger.LogInformation($"{legacy.Length} cases have been deleted");
                }
                catch (Exception ex)
                {
                    Logger.LogError(ex, "Could not cleanup");
                }

                await Task.Delay(3600 * 1000);
            }
        }
Beispiel #4
0
        /// <summary>
        /// Checks if a mounted drive exists and the filesystem type is <see cref="DOKAN_FORMAT"/>.
        /// </summary>
        /// <param name="driveLetter">Letter of drive to check.</param>
        /// <returns><c>true</c>, if the drive with the given <paramref name="driveLetter"/> is a mounted Dokan drive, else <c>false</c>.</returns>
        public static bool IsDokanDrive(char driveLetter)
        {
            bool result = false;

            // Check if this drive was queried before
            if (_dokanDriveLetters.Contains(driveLetter))
            {
                return(true);
            }

            try
            {
                ThreadingUtils.CallWithTimeout(() =>
                {
                    // By checking the given drive's format, we'll find ALL Dokan drives, also those which are added by other MP2 instances (Client/Server), which is good, but we even
                    // find those which are not added to the system by MediaPortal at all, which is not so good.
                    // A better way would be to modify the drive format the DOKAN library uses for its drives. That way, we could use an own drive format type for MP2.
                    // But unfortunately, the drive format cannot be configured in the DOKAN library.
                    // It would be also possible to check the drive's volume label, but I think the check for the drive format is more elegant.
                    DriveInfo driveInfo = new DriveInfo(driveLetter + ":");
                    // Check the IsReady property to avoid DriveNotFoundException
                    result = driveInfo.IsReady && driveInfo.DriveFormat == DOKAN_FORMAT;
                }, DRIVE_TIMEOUT_MS);
            }
            catch (TimeoutException)
            {
                result = true;
            }
            // Cache information only for DOKAN drives, all other (also non-existing) needs to be checked again (i.e. for removable media)
            if (result)
            {
                _dokanDriveLetters.Add(driveLetter);
            }
            return(result);
        }
 void m_AutomationEngine_ExecutionBegin(object sender, ExecutionBeginEventArgs e)
 {
     ThreadingUtils.InvokeControlAction(this, ctl =>
     {
         zOnExecutionStart(EventArgs.Empty);
     });
 }
        public void PollElements(ElementIdentifier identifier, HtmlElement relativeTo, TimeSpan timeout, Action <List <HtmlElement> > callback)
        {
            //Make initial pass at finding element synchronously (in case element is there, don't waste time starting a task)
            List <HtmlElement> results = FindElements(identifier, relativeTo);

            if (results.Count > 0)
            {
                callback(results);
                return;
            }

            //If initial pass returns nothing, start polling task
            Task.Factory.StartNew(() =>
            {
                DateTime start = DateTime.Now;
                bool stop      = false;
                while (!stop)
                {
                    ThreadingUtils.InvokeControlAction(Browser, ctl =>
                    {
                        List <HtmlElement> pollResults = FindElements(identifier, relativeTo);
                        if (pollResults.Count > 0 || DateTime.Now.Subtract(start) >= timeout)
                        {
                            stop = true;
                            callback(pollResults);
                        }
                    });
                    Thread.Sleep(100);
                }
            });
        }
Beispiel #7
0
        /// <summary>
        /// Removes an item from the queue.
        /// </summary>
        /// <param name="item">The dequeued item.</param>
        /// <returns>
        /// The dequeued item, or the default value for the element type if the queue was empty.
        /// </returns>
        public bool Dequeue(out T item)
        {
            item = default(T);
            Node <T> oldHead = null;

            bool haveAdvancedHead = false;

            while (!haveAdvancedHead)
            {
                oldHead = _head;
                Node <T> oldTail     = _tail;
                Node <T> oldHeadNext = oldHead.Next;
                if (oldHead == _head)
                {
                    if (oldHead == oldTail)
                    {
                        if (oldHeadNext == null)
                        {
                            return(false);
                        }
                        ThreadingUtils.CompareAndSwap(ref _tail, oldTail, oldHeadNext);
                    }
                    else
                    {
                        item             = oldHeadNext.Item;
                        haveAdvancedHead = ThreadingUtils.CompareAndSwap(ref _head, oldHead, oldHeadNext);
                    }
                }
            }
            return(true);
        }
Beispiel #8
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="from"></param>
        /// <param name="count"></param>
        /// <param name="operationInfo"></param>
        /// <returns></returns>
        public async Task <IPointsRow[]> GetDecimatedRangeAsync(int from, int count, AsyncOperationInfo operationInfo)
        {
#warning what if underlying collection is not thread safe? Or it decreases its size?!
            await ThreadingUtils.ContinueAtThreadPull(operationInfo);

            IPointsRow[] result;
            if (count > _maxRowsCount) // Decimation required
            {
                var coefficient = (double)count / _maxRowsCount;
                var sourceRows  = _maxRowsCount
                                  .Range()
                                  .AsParallel()
                                  .AsOrdered()
                                  .Select(i => (i * coefficient + from).Round())
                                  .Where(i => i < Source.RowsCount) // To handle possible rounding error
                                  .ToArray();
                return(await Source.ReadRowsAsync(from, sourceRows, operationInfo));
            }
            else
            {
                result = await Source.ReadRowsAsync(from, count, operationInfo);
            }

            return(result);
        }
Beispiel #9
0
        public async Task <PipeReadResult> ReadAsync(PipeReadParameters parameters, CancellationToken cancellation)
        {
            await ThreadingUtils.ContinueAtThreadPull(cancellation);

            var  buffer    = new byte[parameters.BytesExpected];
            uint bytesRead = 0;
            var  status    = _ftdi.Read(buffer, parameters.BytesExpected.ToUInt32(), ref bytesRead);

            if (status == FT_STATUS.FT_OK)
            {
                if (bytesRead < parameters.BytesExpected)
                {
                    return(new PipeReadResult(ReadStatus.PATIALLY_DONE, bytesRead.ToInt32(), buffer.Take(bytesRead.ToInt32())));
                }
                else if (bytesRead == parameters.BytesExpected)
                {
                    return(new PipeReadResult(ReadStatus.DONE, bytesRead.ToInt32(), buffer));
                }
                else
                {
                    throw new InvalidOperationException();
                }
            }
            else
            {
                return(new PipeReadResult(ReadStatus.UNKNOWN_ERROR));
            }
        }
Beispiel #10
0
        async Task daemon()
        {
            await ThreadingUtils.ContinueAtDedicatedThread();

            while (true)
            {
                try
                {
                    using var scope = ScopeFactory.CreateScope();
                    using var db    = scope.ServiceProvider.GetRequiredService <RunnerContext>();

                    var hang = await db.RunResults
                               .IncludeGroup(API.Models.EntityGroups.ALL, db)
                               .AsNoTracking()
                               .ToArrayAsync();

                    hang = hang
                           .Where(d => d.ResultBase.Result == API.Models.RunResult.Running &&
                                  DateTime.UtcNow - d.ResultBase.StartTime > TimeSpan.FromMinutes(3))
                           .ToArray();
                    db.RunResults.RemoveRange(hang);
                    await db.SaveChangesAsync();
                }
                catch (Exception ex)
                {
                    Debugger.Break();
                }

                await Task.Delay(60 * 1000);
            }
        }
Beispiel #11
0
        public async Task <PipeReadResult> ReadAsync(PipeReadParameters parameters, CancellationToken cancellation)
        {
            await ThreadingUtils.ContinueAtThreadPull();

            var buffer = new byte[parameters.BytesExpected];

            for (int i = 0; i < buffer.Length; i++)
            {
                var data = _port.ReadByte();
                if (data == -1)
                {
                    await Task.Delay(1, cancellation);

                    i--;
                }
                else
                {
                    buffer[i] = data.ToByte();
                }

                cancellation.ThrowIfCancellationRequested();
            }

            return(new PipeReadResult(ReadStatus.DONE, buffer.Length, buffer));
        }
Beispiel #12
0
        /// <summary>
        /// Inserts the specified element at the tail of this queue.
        /// </summary>
        /// <param name="item">The item to insert in the queue.</param>
        public void Enqueue(T item)
        {
            Node <T> oldTail = null;
            Node <T> oldTailNext;
            Node <T> newNode         = new Node <T>(item);
            bool     newNodeWasAdded = false;

            while (!newNodeWasAdded)
            {
                oldTail     = _tail;
                oldTailNext = oldTail.Next;

                if (_tail == oldTail)
                {
                    if (oldTailNext == null)
                    {
                        newNodeWasAdded = ThreadingUtils.CompareAndSwap(ref _tail.Next, null, newNode);
                    }
                    else
                    {
                        ThreadingUtils.CompareAndSwap(ref _tail, oldTail, oldTailNext);
                    }
                }
            }
            ThreadingUtils.CompareAndSwap(ref _tail, oldTail, newNode);
        }
Beispiel #13
0
        async Task updateAwailablePortsLoop(CancellationToken cancellation)
        {
            await ThreadingUtils.ContinueAtDedicatedThread(cancellation);

            var period = new PeriodDelay(1000);

            while (true)
            {
                try
                {
                    using (await Locker.AcquireAsync())
                    {
                        var devices = getAllDevices();
                        PortNames = devices.Length.Range().Select(i => PORT_PREFIX + i);
                    }
                }
                catch (OperationCanceledException)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    Logger.LogError(null, $"Ошибка обновления списка устройств", ex);
                }

                await period.WaitTimeLeftAsync(cancellation);
            }
        }
Beispiel #14
0
 /// <summary>
 /// Returns the first actual (non-header) node on list.
 /// </summary>
 /// <returns>First node.</returns>
 Node <T> First()
 {
     for (; ;)
     {
         Node <T> h     = _head;
         Node <T> t     = _tail;
         Node <T> first = h.Next;
         if (h == _head)
         {
             if (h == t)
             {
                 if (first == null)
                 {
                     return(null);
                 }
                 else
                 {
                     ThreadingUtils.CompareAndSwap(ref _tail, t, first);
                 }
             }
             else
             {
                 if (first.Item != null)
                 {
                     return(first);
                 }
                 else // remove deleted node and continue
                 {
                     ThreadingUtils.CompareAndSwap(ref _head, h, first);
                 }
             }
         }
     }
 }
Beispiel #15
0
        public bool IsBlockWalkable(int blockX, int blockY)
        {
            ThreadingUtils.assertChildThread();

            if (CollisionUtils.IsBlockBlocking(GetBlockType(blockX, blockY)))
            {
                return(false);
            }

            Rect blockBounds = new Rect(blockX * WorldGrid.BlockSize.X, blockY * WorldGrid.BlockSize.Y, WorldGrid.BlockSize.X, WorldGrid.BlockSize.Y);

            if (ContainedObjects != null)
            {
                lock (ContainedObjects)
                {
                    foreach (var containedObject in ContainedObjects)
                    {
                        lock (containedObject)
                        {
                            if (containedObject.IsBlocking() && containedObject.BlockingBounds.Intersects(blockBounds))
                            {
                                return(false);
                            }
                        }
                    }
                }
            }

            return(true);
        }
Beispiel #16
0
        async Task daemon()
        {
            await ThreadingUtils.ContinueAtDedicatedThread();

            while (true)
            {
                try
                {
                    using var scope = ScopeFactory.CreateScope();
                    var db = scope.ServiceProvider.GetRequiredService <RunnerContext>();

                    var toUpdate = await db.RunResults
                                   .AsNoTracking()
                                   .IncludeGroup(API.Models.EntityGroups.ALL, db)
                                   .Where(r => !r.ResultBase.State.IsFinal && r.ResultBase.State.NextStateUpdate != null && r.ResultBase.State.NextStateUpdate.Value < DateTime.UtcNow)
                                   .ToArrayAsync();

                    foreach (var r in toUpdate)
                    {
                        Producer.FireUpdateTestResultState(new UpdateTestResultStateMessage(r.ResultBase.TestId, r.Id, r.ResultBase.SourceId, r.ResultBase.State));
                    }
                }
                catch (Exception ex)
                {
                    Debugger.Break();
                }

                await Task.Delay(10 * 1000);
            }
        }
Beispiel #17
0
        private void garbageCollect()
        {
            ThreadingUtils.assertMainThread();

            var partsUnloaded = 0;
            var stopwatch     = new Stopwatch();

            stopwatch.Start();

            foreach (var part in loadedParts)
            {
                var key          = part.Key;
                var shouldRemove = shouldRemoveDuringGarbageCollection(part.Key, part.Value);

                if (shouldRemove)
                {
                    if (UnloadChunk(key))
                    {
                        partsUnloaded++;
                    }
                }
            }

            stopwatch.Stop();

            if (partsUnloaded > 0)
            {
                GameConsole.WriteLine("ChunkLoading", "Garbage Collector unloaded " + partsUnloaded + " " + GetType().Name + " parts took " + stopwatch.ElapsedMilliseconds + "ms");
            }
        }
 private void zRefreshVariables()
 {
     ThreadingUtils.InvokeControlAction(tlvVariables, tv =>
     {
         tlvVariables.SetObjects(m_AutomationEngine.DataContext.StateVariables.Values, true);
         tlvVariables.RefreshObjects(m_AutomationEngine.DataContext.StateVariables.Values.ToList());
     });
 }
 void m_AutomationEngine_StepBegin(object sender, StepEventArgs e)
 {
     ThreadingUtils.InvokeControlAction(tlvSequence, tlv =>
     {
         tlv.ExpandToObject(m_AutomationEngine.CurrentStep);
         tlv.RefreshObject(m_AutomationEngine.CurrentStep);
         tlv.Refresh();
     });
 }
Beispiel #20
0
        public void DeletePackageFiles(UFramePackage package)
        {
            var packagePath = Path.Combine(Path.Combine(ApplicationPath, "uFramePackages"), package.Id);

            ThreadingUtils.DispatchOnMainThread(() =>
            {
                FileUtil.DeleteFileOrDirectory(packagePath);
            });
        }
Beispiel #21
0
        public async Task <PipeWriteResult> WriteAsync(PipeWriteParameters parameters, CancellationToken cancellation)
        {
            await ThreadingUtils.ContinueAtThreadPull();

            var buffer = parameters.Buffer.ToArray();

            _port.Write(buffer, 0, buffer.Length);

            return(new PipeWriteResult(WriteStatus.DONE, buffer.Length));
        }
        private void zRefreshSteps()
        {
            zBuildStepIndex();
            ThreadingUtils.InvokeControlAction(tlvSequence, tlv =>
            {
                tlv.SetObjects(m_AutomationEngine.Sequence, true);
            });

            zRefreshVariables();
        }
Beispiel #23
0
        public async Task <IPointsRow[]> ReadRowsAsync(int firstRowIndex, int rowsCount, AsyncOperationInfo operationInfo)
        {
            await ThreadingUtils.ContinueAtThreadPull(operationInfo);

            var indexes = rowsCount
                          .Range()
                          .Select(i => i + firstRowIndex)
                          .ToArray();

            return(await readRowsAsync(firstRowIndex, indexes, true, operationInfo));
        }
        void m_AutomationEngine_ExecutionComplete(object sender, ExecutionCompleteEventArgs e)
        {
            zRefreshVariables();
            m_Executing = false;
            ThreadingUtils.InvokeControlAction(this, ctl =>
            {
                zResumeRecording();
                zSelectAllStepElements();

                zOnExecutionStop(EventArgs.Empty);
            });
        }
Beispiel #25
0
        public static async Task LogRequestAsync(IList <byte> requestBytes)
        {
            var time = DateTime.Now;
            await ThreadingUtils.ContinueAtThreadPull();

            using (await _ioLogStream.Locker.AcquireAsync())
            {
                var data = $"{time.ToString(Logging.Logger.TIME_FORMAT)} Request[{requestBytes.Count}] >> ".PadRight(40, ' ') + requestBytes.Select(b => b.ToString("X2")).Aggregate(" ");
                _ioLogStream.Object.WriteLine(data);
                _ioLogStream.Object.Flush();
            }
        }
Beispiel #26
0
        public async Task <TResponse> DeserializeResponseAsync(IResponseFuture inputStream, AsyncOperationInfo operationInfo)
        {
            var sw = Stopwatch.StartNew();
            await ThreadingUtils.ContinueAtThreadPull();

            var       loggedResponseFuture = new LoggingResponseFutureDecorator(inputStream, MAX_AMOUNT_OF_BYTES_INSIDE_LOG_ENTRY);
            TResponse response             = null;

            using (Logger.Indent)
            {
                Logger.LogInfo(null, "Чтение ответа...");
                try
                {
                    response = await deserializeResponseAsync(loggedResponseFuture, operationInfo);

                    logDataRead();
                }
                catch (TimeoutException ex)
                {
                    logError(ex);

                    response = BuildErrorResponse(RequestStatus.READ_TIMEOUT);
                }
                catch (Exception ex)
                {
                    logError(ex);

                    response = BuildErrorResponse(RequestStatus.DESERIALIZATION_ERROR);
                }
            }

            return(response);

            void logDataRead()
            {
                Logger.LogInfo(null, $"Пакет ответа был успешно прочитан{Global.NL}Полная длина: {loggedResponseFuture.ReadCount}, длительность чтения: {sw.Elapsed.TotalMilliseconds.ToString("F2")} мс{getBufferRepresentation()}");
            }

            void logError(Exception ex)
            {
                Logger.LogError(null, $"Ошибка во время чтения/десериализации пакета. Было прочитано: {loggedResponseFuture.ReadCount}, длительность чтения: {sw.Elapsed.TotalMilliseconds.ToString("F2")} мс{getBufferRepresentation()}", ex);
            }

            string getBufferRepresentation()
            {
                var tooManyData = loggedResponseFuture.StorageCount < loggedResponseFuture.ReadCount;

                return($"{Global.NL}Первые {loggedResponseFuture.Capacity} байт из {loggedResponseFuture.ReadCount}".IfOrDefault(tooManyData) +
                       $"{Global.NL}Данные<HEX>:{loggedResponseFuture.Storage.Select(b => b.ToString("X2").PadLeft(3)).Aggregate(" ")}" +
                       $"{Global.NL}Данные<DEC>:{loggedResponseFuture.Storage.Select(b => b.ToString("D3").PadLeft(3)).Aggregate(" ")}");
            }
        }
        public static bool IsHitableBlockHitted(Rect hitboxBounds, string interiorID = null)
        {
            ThreadingUtils.assertMainThread();

            if (interiorID == Interior.Outside)
            {
                // Check if blocks are of type blocking
                Point topLeft     = GeometryUtils.GetChunkPosition(hitboxBounds.Left, hitboxBounds.Top, WorldGrid.BlockSize.X, WorldGrid.BlockSize.Y);
                Point bottomRight = GeometryUtils.GetChunkPosition(hitboxBounds.Right, hitboxBounds.Bottom, WorldGrid.BlockSize.X, WorldGrid.BlockSize.Y);

                for (int blockX = topLeft.X; blockX <= bottomRight.X; blockX++)
                {
                    for (int blockY = topLeft.Y; blockY <= bottomRight.Y; blockY++)
                    {
                        Point          chunkPos       = GeometryUtils.GetChunkPosition(blockX, blockY, WorldGrid.WorldChunkBlockSize.X, WorldGrid.WorldChunkBlockSize.Y);
                        WorldGridChunk worldGridChunk = SimulationGame.World.GetFromChunkPoint(chunkPos.X, chunkPos.Y);

                        int blockType = worldGridChunk.GetBlockType(blockX, blockY);

                        if (IsBlockHitable(blockType))
                        {
                            return(true);
                        }
                    }
                }
            }
            else
            {
                Interior interior = SimulationGame.World.InteriorManager.Get(interiorID);

                // Check if blocks are of type blocking
                Point topLeft     = GeometryUtils.GetChunkPosition(hitboxBounds.Left, hitboxBounds.Top, WorldGrid.BlockSize.X, WorldGrid.BlockSize.Y);
                Point bottomRight = GeometryUtils.GetChunkPosition(hitboxBounds.Right, hitboxBounds.Bottom, WorldGrid.BlockSize.X, WorldGrid.BlockSize.Y);

                for (int blockX = topLeft.X; blockX <= bottomRight.X; blockX++)
                {
                    for (int blockY = topLeft.Y; blockY <= bottomRight.Y; blockY++)
                    {
                        int blockType = interior.GetBlockType(blockX, blockY);

                        if (IsBlockHitable(blockType))
                        {
                            return(true);
                        }
                    }
                }
            }

            return(false);
        }
Beispiel #28
0
        async void accquireDaemon()
        {
            await ThreadingUtils.ContinueAtDedicatedThread();

            while (true)
            {
                var parameters = "<Operation>";
                for (int i = 0; i < Global.Random.Next(1, 4); i++)
                {
                    parameters += $"<Step{i}>";

                    for (int k = 0; k < Global.Random.Next(2, 10); k++)
                    {
                        parameters += $"<p name=\"{Global.Random.NextRUWord()}\">{Global.Random.NextObjFrom(Global.Random.NextDateTime(default, DateTime.UtcNow).ToString(), Global.Random.NextDouble(0, 10000).ToString(), Global.Random.Next(-10000, 10000).ToString(), Global.Random.NextRUWord().ToString(), Global.Random.NextENWord().ToString())}</p>";
        /// <summary>
        /// Tries to get text contents from the Windows clipboard. If the clipboard contains any other type then text, the returned result will be <c>false</c>.
        /// </summary>
        /// <returns><c>true</c> if text could be retrieved.</returns>
        public bool GetClipboardText(out string text)
        {
            string           result        = null;
            ManualResetEvent finishedEvent = new ManualResetEvent(false);
            Thread           thread        = ThreadingUtils.RunSTAThreaded(() => GetClipboardText_STA(finishedEvent, ref result));

            if (!finishedEvent.WaitOne(MAX_WAIT_MS))
            {
                thread.Abort();
            }

            finishedEvent.Close();
            text = result;
            return(!string.IsNullOrWhiteSpace(result));
        }
Beispiel #30
0
 public override void Send(string subject, string message)
 {
     if (m_UIContext != null)
     {
         ThreadingUtils.InvokeControlAction(m_UIContext, ctl =>
         {
             frmPopup frm = new frmPopup(subject, message);
             frm.Show();
         });
     }
     else
     {
         System.Diagnostics.Debug.WriteLine("Unable to show popup notification as no UIContext was provided.");
     }
 }