private async Task <(Stream stream, bool fromStorage)> GetContextStreamAsync(
            TournamentBracketRequest request,
            TournamentBracketContent content,
            CompositeDisposable disposables,
            CancellationToken cancellationToken
            )
        {
            // Validate parameters.
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }
            if (disposables == null)
            {
                throw new ArgumentNullException(nameof(disposables));
            }

            // The algorithm is this:
            // If there is content, use that.
            // If there is not content, then try to get from challonge.
            // If there is no content, try to get from persistence
            // If it can't be retrieved, throw.

            // Check the request for content.
            if (content != null &&
                content.MediaType.Type == "text" &&
                content.MediaType.SubTypeWithoutSuffix == "html"
                )
            {
                // Return a streamreader.
                return(content.Content, false);
            }

            // Try and get it from challonge.
            Stream stream = await GetStreamFromChallongeAsync(
                request, disposables, cancellationToken
                )
                            .ConfigureAwait(false);

            // If not null, return.
            if (stream != null)
            {
                return(stream, false);
            }

            // Get the reader from storage.
            stream = await GetStreamFromStorageAsync(
                request, disposables, cancellationToken
                ).ConfigureAwait(false);

            // If there is no stream at this point, throw.
            if (stream == null)
            {
                throw new InvalidOperationException(
                          $"Could not retrieve content for URL \"{request.Url}\" from user-sumbmitted content, Challonge, or storage.");
            }

            // Return the reader.
            return(stream, true);
        }
        public async Task <TournamentBracketResponse> GetTournamentBracketAsync(
            TournamentBracketRequest request,
            TournamentBracketContent content,
            CancellationToken cancellationToken)
        {
            // Validate parameters.
            // Note: The content parameter can be null.
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            // If the url is null, throw.
            if (request.Url == null)
            {
                throw new InvalidOperationException(
                          $"The {nameof(request.Url)} property on the {nameof(request)} parameter cannot be null.");
            }

            // The disposables.
            using var disposables = new CompositeDisposable();

            // The page content.
            TournamentBracketPage page;

            // Get the content stream.
            (Stream rawStream, bool fromStorage) = await GetContextStreamAsync(
                request, content, disposables, cancellationToken
                ).ConfigureAwait(false);

            // Add the raw stream to the disposables.
            disposables.Add(rawStream);

            // If there is no stream, copy it.
            if (!(rawStream is MemoryStream stream))
            {
                // Create a new one.
                stream = new MemoryStream();

                // Copy.
                await rawStream.CopyToAsync(stream, 4096, cancellationToken)
                .ConfigureAwait(false);
            }

            // Add the stream to the disposables.
            disposables.Add(stream);

            // Set the position of the stream back.
            stream.Position = 0;

            // Create a reader.
            using TextReader reader = new StreamReader(stream);

            // Parse.
            page = await _parser.ParseTournamentBracketPageAsync(reader, cancellationToken)
                   .ConfigureAwait(false);

            // Everything was successful at this point, reset the stream and persist.
            stream.Position = 0;

            // Persist if this wasn't from storage to begin with.
            if (!fromStorage)
            {
                await PersistContentAsync(request, stream, cancellationToken)
                .ConfigureAwait(false);
            }

            // Return.
            return(new TournamentBracketResponse {
                Request = request,
                PageContent = page.PageContent,
                Bracket = page.Bracket,
                TargetingKeyValues = page.TargetingKeyValues,
                MetaList = page.MetaList
            });
        }