private async Task SynchronizeDatabaseAsync()
        {
            var cancellationToken = this._synchronizationTaskCancellationTokenSource.Token;

            while (!cancellationToken.IsCancellationRequested)
            {
                var getThreatListUpdatesTask = GetThreatListUpdatesAsync(this);
                var(threatListUpdateResponse, delayToDate) = await getThreatListUpdatesTask.ConfigureAwait(false);

                if (threatListUpdateResponse != null)
                {
                    foreach (var threatListUpdateResult in threatListUpdateResponse.Results)
                    {
                        var threatListWaitToDate = threatListUpdateResult.RetrievedThreatList.WaitToDate;
                        if (threatListWaitToDate != null && threatListWaitToDate < delayToDate)
                        {
                            delayToDate = threatListWaitToDate.Value;
                        }

                        var synchronizeThreatListTask = SynchronizeThreatListAsync(this, threatListUpdateResult);
                        await synchronizeThreatListTask.ConfigureAwait(false);
                    }
                }

                var delayToTask = DelayToAsync(this, delayToDate);
                await delayToTask.ConfigureAwait(false);
            }

            // <summary>
            //      Delay to a Date Asynchronously.
            // </summary>
            async Task DelayToAsync(BrowsingDatabaseManager @this, DateTime cDate)
            {
                try {
                    var cCancellationToken = @this._synchronizationTaskCancellationTokenSource.Token;
                    var cDelayToTask       = TaskExtension.DelayTo(cDate, cCancellationToken);
                    await cDelayToTask.ConfigureAwait(false);
                }
                catch (OperationCanceledException) {
                    // ...
                    //
                    // We don't care if the cancellation token is cancelled.
                }
            }

            // <summary>
            //      Get Threat List Updates Asynchronously.
            // </summary>
            async Task <(ThreatListUpdateResponse, DateTime)> GetThreatListUpdatesAsync(BrowsingDatabaseManager @this)
            {
                var cDelayToDate = DateTime.UtcNow.AddMinutes(30);

                try {
                    IEnumerable <ThreatListDescriptor> cThreatListDescriptors = @this._updateConstraints.Keys;
                    if (@this._updateConstraints.Count == 0)
                    {
                        // ...
                        //
                        // If the database synchronizer is not restricted to specific threat lists, we retrieve all
                        // available threat lists from the Google Safe Browsing API. We don't cache the result in case
                        // new threat lists are made available between synchronization iterations.
                        //
                        // Throws an exception if the operation fails.
                        var cGetThreatListDescriptorsTask = @this._client.GetThreatListDescriptorsAsync();
                        cThreatListDescriptors = await cGetThreatListDescriptorsTask.ConfigureAwait(false);
                    }

                    // ...
                    //
                    // Retrieve the threat lists from the database. Throws an exception if the operation fails.
                    var cGetThreatListsTask = @this._database.GetThreatListsAsync(cThreatListDescriptors);
                    var cThreatLists        = await cGetThreatListsTask.ConfigureAwait(false);

                    ThreatListUpdateRequestBuilder cThreatListUpdateRequestBuilder = null;
                    foreach (var cThreatList in cThreatLists)
                    {
                        if (cThreatList.Expired)
                        {
                            cThreatListUpdateRequestBuilder = cThreatListUpdateRequestBuilder ?? ThreatListUpdateRequest.Build();
                            var cThreatListDescriptor = cThreatList.Descriptor;
                            var cThreatListState      = cThreatList.State;
                            @this._updateConstraints.TryGetValue(cThreatListDescriptor, out var cThreatListUpdateConstraints);
                            cThreatListUpdateRequestBuilder.AddQuery(b => {
                                b.SetThreatListDescriptor(cThreatListDescriptor);
                                b.SetThreatListState(cThreatListState);
                                b.SetUpdateConstraints(cThreatListUpdateConstraints);
                                return(b.Build());
                            });
                        }
                        else
                        {
                            if (cThreatList.WaitToDate != null && cThreatList.WaitToDate < cDelayToDate)
                            {
                                // ...
                                //
                                // If the current threat list's wait to date is earlier than the previous threat
                                // list's wait to date, take the current the threat list's wait to date instead.
                                cDelayToDate = cThreatList.WaitToDate.Value;
                            }
                        }
                    }

                    ThreatListUpdateResponse cThreatListUpdateResponse = null;
                    if (cThreatListUpdateRequestBuilder != null)
                    {
                        // ...
                        //
                        // Throws an exception if the operation fails.
                        var cThreatListUpdateRequest  = cThreatListUpdateRequestBuilder.Build();
                        var cGetThreatListUpdatesTask = @this._client.GetThreatListUpdatesAsync(cThreatListUpdateRequest);
                        cThreatListUpdateResponse = await cGetThreatListUpdatesTask.ConfigureAwait(false);
                    }

                    return(cThreatListUpdateResponse, cDelayToDate);
                }
                catch {
                    return(null, cDelayToDate);
                }
            }

            // <summary>
            //      Synchronize Threat List Asynchronously.
            // </summary>
            async Task SynchronizeThreatListAsync(BrowsingDatabaseManager @this, ThreatListUpdateResult cThreatListUpdateResult)
            {
                var cSynchronizationStartDate = DateTime.UtcNow;
                var cThreatList = cThreatListUpdateResult.RetrievedThreatList;

                try {
                    var cSha256HashPrefixes = cThreatListUpdateResult.ThreatsToAdd;
                    if (cThreatListUpdateResult.IsFullUpdate)
                    {
                        // ...
                        //
                        // Throws an exception if the operation fails.
                        var cModifyThreatListTask = @this._database.StoreThreatListAsync(cThreatList, cSha256HashPrefixes);
                        await cModifyThreatListTask.ConfigureAwait(false);
                    }
                    else if (cThreatListUpdateResult.IsPartialUpdate)
                    {
                        // ...
                        //
                        // Throws an exception if the operation fails.
                        var cIndices = cThreatListUpdateResult.ThreatsToRemove;
                        var cModifyThreatListTask = @this._database.ModifyThreatListAsync(cThreatList, cSha256HashPrefixes, cIndices);
                        await cModifyThreatListTask.ConfigureAwait(false);
                    }

                    // ...
                    //
                    // Throws an exception if the operation fails.
                    var cComputeThreatListChecksumTask = @this._database.ComputeThreatListChecksumAsync(cThreatList.Descriptor);
                    var cThreatListChecksum            = await cComputeThreatListChecksumTask.ConfigureAwait(false);

                    if (cThreatListChecksum != cThreatListUpdateResult.RetrievedThreatListChecksum)
                    {
                        // ...
                        //
                        // Throws an exception if the operation fails.
                        cThreatList = ThreatList.CreateInvalid(cThreatList.Descriptor);
                        var cUpdateConstraints        = cThreatListUpdateResult.Query.UpdateConstraints;
                        var cGetThreatListUpdatesTask = @this._client.GetThreatListUpdatesAsync(cThreatList, cUpdateConstraints);
                        var cThreatListUpdateRequest  = await cGetThreatListUpdatesTask.ConfigureAwait(false);

                        cThreatListUpdateResult = cThreatListUpdateRequest.Results.First();
                        cSha256HashPrefixes     = cThreatListUpdateResult.ThreatsToAdd;
                        if (cThreatListUpdateResult.IsFullUpdate)
                        {
                            // ...
                            //
                            // Throws an exception if the operation fails.
                            cThreatList = cThreatListUpdateResult.RetrievedThreatList;
                            var cModifyThreatListTask = @this._database.StoreThreatListAsync(cThreatList, cSha256HashPrefixes);
                            await cModifyThreatListTask.ConfigureAwait(false);
                        }
                    }

                    // ...
                    //
                    // Invoke threat list synchronization completed event.
                    var cSynchronizationCompletionDate = DateTime.UtcNow;
                    @this.OnThreatListSynchronizationCompleted(new ThreatListSynchronizationCompletedEventArgs(
                                                                   cThreatList,
                                                                   cSynchronizationStartDate,
                                                                   cSynchronizationCompletionDate
                                                                   ));
                }
                catch (Exception cEx) {
                    // ...
                    //
                    // Invoke threat list synchronization failed event.
                    var cSynchronizationFailureDate = DateTime.UtcNow;
                    @this.OnThreatListSynchronizationFailed(new ThreatListSynchronizationFailedEventArgs(
                                                                cThreatList,
                                                                cSynchronizationStartDate,
                                                                cSynchronizationFailureDate,
                                                                cEx
                                                                ));
                }
            }
        }