public void BoldlyGoTest()
        {
            var model = new ApplicationModel(new TracingWriterEnvironment());

            var script = new[]
            {
                "space",
                "the final frontier",
                "these are the voyages of the starship enterprise",
                "its five year mission",
                "to explore strange new worlds",
                "to seek out new life",
                "and new civilizations",
                "to boldly go where no man has gone before"
            };

            for (var line = 0; line < script.Length - 1; line++)
            {
                var lineSequence = TileSequence.FromRaw(script[line]);

                ApplicationRobotAction action;
                do
                {
                    action = ApplicationRobot.GetNextCompletionAction(model, lineSequence);
                    action.ExecuteItem(model);
                }while (!action.IsComplete);
            }

            var sequence = TileSequence.FromRaw(script[^ 1]);
        private static int CountClicks(ApplicationModel model, TileSequence words, double errorRate, string traceName)
        {
            Assert.IsInstanceOf <TracingWriterEnvironment>(model.Environment);

            var random = new Random(0);

            var count      = 0;
            var errorCount = 0;

            var hasNotified        = false;
            var expectedIsComplete = false;

            var actionIsComplete = false;
            var isGood           = false;

            void OnNotifyCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
            {
                Assert.IsFalse(hasNotified, "No changes after model update notification");
            }

            void OnApplicationModelUpdated(object sender, ApplicationModelUpdateEventArgs e)
            {
                Assert.IsFalse(hasNotified, "No previous model update notification");
                hasNotified = true;

                Assert.AreEqual(isGood && actionIsComplete, isGood && e.IsComplete);

                if (e.IsComplete)
                {
                    expectedIsComplete = true;
                }
                else
                {
                    expectedIsComplete = false;
                }
            }

            var collections = new INotifyCollectionChanged[] { model.HeadItems, model.TailItems, model.SuggestionInterstitials, model.SuggestionLists };

            foreach (var collection in collections)
            {
                collection.CollectionChanged += OnNotifyCollectionChanged;
            }
            model.ApplicationModelUpdate += OnApplicationModelUpdated;

            bool done;

            do
            {
                ApplicationRobotAction action;

                if (errorCount < 100 && random.NextDouble() < errorRate)
                {
                    isGood = false;
                    action = ApplicationRobot.GetRandom(model, random);
                    errorCount++;
                }
                else if (random.NextDouble() < errorRate / 20.0)
                {
                    isGood = false;
                    action = ApplicationRobot.GetRandom(model, random);
                    errorCount++;
                }
                else
                {
                    isGood = true;
                    action = ApplicationRobot.GetNextCompletionAction(model, words);
                }

                var item = action.GetItem(model);
                if (item is InterstitialNonItem)
                {
                    Assert.IsNotInstanceOf <InterstitialNonItem>(item, "Should never click on a non-item");
                }

                hasNotified      = false;
                actionIsComplete = action.IsComplete;
                action.ExecuteItem(model);
                Assert.IsTrue(hasNotified, "We should have seen a notification");
                Assert.AreEqual(isGood && expectedIsComplete, isGood && action.IsComplete, "IsComplete in action and notification should match");

                CheckModelLinkage(model);

                count++;
                done = isGood && action.IsComplete;

#if false
                if (9900 <= count)
                {
                    if (Debugger.IsAttached)
                    {
                        var item = action.GetItem(model);
                        Debug.WriteLine($"{count}: {isGood} {action.Target} {action.Index}.{action.SubIndex} - {item.GetType().Name} - {item}");
                    }

                    if (9950 <= count)
                    {
                        Assert.IsTrue(count < 10000, "Clicking ends in reasonable time");
                    }
                }
#else
                Assert.IsTrue(count < 10000, "Clicking ends in reasonable time");
#endif
            }while (!done);

            foreach (var collection in collections)
            {
                collection.CollectionChanged -= OnNotifyCollectionChanged;
            }
            model.ApplicationModelUpdate -= OnApplicationModelUpdated;


            // Check there is but one action needed to re-establish text.
            var reestablishAction = ApplicationRobot.GetNextEstablishingAction(model, words);
            Assert.IsNotNull(reestablishAction);
            Assert.IsFalse(reestablishAction.IsComplete);
            reestablishAction.ExecuteItem(model);

            var nullAction = ApplicationRobot.GetNextEstablishingAction(model, words);
            Assert.IsNull(nullAction);

            // Check there is now a single action to complete the text.
            var completionAction = ApplicationRobot.GetNextCompletionAction(model, words);
            Assert.IsNotNull(completionAction);
            Assert.IsTrue(completionAction.IsComplete);
            completionAction.ExecuteItem(model);

            SaveTrace(model, traceName);

            return(count);
        }