Exemplo n.º 1
0
        public void WriteJson(SimpleJson.Writer writer)
        {
            writer.WriteObjectStart();

            writer.WriteProperty("callstack", callStack.WriteJson);
            writer.WriteProperty("outputStream", w => Json.WriteListRuntimeObjs(w, outputStream));

            // choiceThreads: optional
            // Has to come BEFORE the choices themselves are written out
            // since the originalThreadIndex of each choice needs to be set
            bool hasChoiceThreads = false;

            foreach (Choice c in currentChoices)
            {
                c.originalThreadIndex = c.threadAtGeneration.threadIndex;

                if (callStack.ThreadWithIndex(c.originalThreadIndex) == null)
                {
                    if (!hasChoiceThreads)
                    {
                        hasChoiceThreads = true;
                        writer.WritePropertyStart("choiceThreads");
                        writer.WriteObjectStart();
                    }

                    writer.WritePropertyStart(c.originalThreadIndex);
                    c.threadAtGeneration.WriteJson(writer);
                    writer.WritePropertyEnd();
                }
            }

            if (hasChoiceThreads)
            {
                writer.WriteObjectEnd();
                writer.WritePropertyEnd();
            }


            writer.WriteProperty("currentChoices", w => {
                w.WriteArrayStart();
                foreach (var c in currentChoices)
                {
                    Json.WriteChoice(w, c);
                }
                w.WriteArrayEnd();
            });


            writer.WriteObjectEnd();
        }
Exemplo n.º 2
0
        public void WriteJson(SimpleJson.Writer writer)
        {
            writer.WriteObjectStart();
            foreach (var keyVal in _globalVariables)
            {
                var name = keyVal.Key;
                var val  = keyVal.Value;

                if (dontSaveDefaultValues)
                {
                    // Don't write out values that are the same as the default global values
                    Runtime.Object defaultVal;
                    if (_defaultGlobalVariables.TryGetValue(name, out defaultVal))
                    {
                        if (RuntimeObjectsEqual(val, defaultVal))
                        {
                            continue;
                        }
                    }
                }


                writer.WritePropertyStart(name);
                Json.WriteRuntimeObject(writer, val);
                writer.WritePropertyEnd();
            }
            writer.WriteObjectEnd();
        }
Exemplo n.º 3
0
        public static void WriteRuntimeContainer(SimpleJson.Writer writer, Container container, bool withoutName = false)
        {
            writer.WriteArrayStart();

            foreach (var c in container.content)
            {
                WriteRuntimeObject(writer, c);
            }

            // Container is always an array [...]
            // But the final element is always either:
            //  - a dictionary containing the named content, as well as possibly
            //    the key "#" with the count flags
            //  - null, if neither of the above
            var namedOnlyContent = container.namedOnlyContent;
            var countFlags       = container.countFlags;
            var hasNameProperty  = container.name != null && !withoutName;

            bool hasTerminator = namedOnlyContent != null || countFlags > 0 || hasNameProperty;

            if (hasTerminator)
            {
                writer.WriteObjectStart();
            }

            if (namedOnlyContent != null)
            {
                foreach (var namedContent in namedOnlyContent)
                {
                    var name           = namedContent.Key;
                    var namedContainer = namedContent.Value as Container;
                    writer.WritePropertyStart(name);
                    WriteRuntimeContainer(writer, namedContainer, withoutName: true);
                    writer.WritePropertyEnd();
                }
            }

            if (countFlags > 0)
            {
                writer.WriteProperty("#f", countFlags);
            }

            if (hasNameProperty)
            {
                writer.WriteProperty("#n", container.name);
            }

            if (hasTerminator)
            {
                writer.WriteObjectEnd();
            }
            else
            {
                writer.WriteNull();
            }

            writer.WriteArrayEnd();
        }
Exemplo n.º 4
0
        static void WriteInkList(SimpleJson.Writer writer, ListValue listVal)
        {
            var rawList = listVal.value;

            writer.WriteObjectStart();

            writer.WritePropertyStart("list");

            writer.WriteObjectStart();

            foreach (var itemAndValue in rawList)
            {
                var item    = itemAndValue.Key;
                int itemVal = itemAndValue.Value;

                writer.WritePropertyNameStart();
                writer.WritePropertyNameInner(item.originName ?? "?");
                writer.WritePropertyNameInner(".");
                writer.WritePropertyNameInner(item.itemName);
                writer.WritePropertyNameEnd();

                writer.Write(itemVal);

                writer.WritePropertyEnd();
            }

            writer.WriteObjectEnd();

            writer.WritePropertyEnd();

            if (rawList.Count == 0 && rawList.originNames != null && rawList.originNames.Count > 0)
            {
                writer.WritePropertyStart("origins");
                writer.WriteArrayStart();
                foreach (var name in rawList.originNames)
                {
                    writer.Write(name);
                }
                writer.WriteArrayEnd();
                writer.WritePropertyEnd();
            }

            writer.WriteObjectEnd();
        }
Exemplo n.º 5
0
 public static void WriteDictionaryRuntimeObjs(SimpleJson.Writer writer, Dictionary <string, Runtime.Object> dictionary)
 {
     writer.WriteObjectStart();
     foreach (var keyVal in dictionary)
     {
         writer.WritePropertyStart(keyVal.Key);
         WriteRuntimeObject(writer, keyVal.Value);
         writer.WritePropertyEnd();
     }
     writer.WriteObjectEnd();
 }
Exemplo n.º 6
0
            public void WriteJson(SimpleJson.Writer writer)
            {
                writer.WriteObjectStart();

                // callstack
                writer.WritePropertyStart("callstack");
                writer.WriteArrayStart();
                foreach (CallStack.Element el in callstack)
                {
                    writer.WriteObjectStart();
                    if (!el.currentPointer.isNull)
                    {
                        writer.WriteProperty("cPath", el.currentPointer.container.path.componentsString);
                        writer.WriteProperty("idx", el.currentPointer.index);
                    }

                    writer.WriteProperty("exp", el.inExpressionEvaluation);
                    writer.WriteProperty("type", (int)el.type);

                    if (el.temporaryVariables.Count > 0)
                    {
                        writer.WritePropertyStart("temp");
                        Json.WriteDictionaryRuntimeObjs(writer, el.temporaryVariables);
                        writer.WritePropertyEnd();
                    }

                    writer.WriteObjectEnd();
                }
                writer.WriteArrayEnd();
                writer.WritePropertyEnd();

                // threadIndex
                writer.WriteProperty("threadIndex", threadIndex);

                if (!previousPointer.isNull)
                {
                    writer.WriteProperty("previousContentObject", previousPointer.Resolve().path.ToString());
                }

                writer.WriteObjectEnd();
            }
Exemplo n.º 7
0
        void WriteJson(SimpleJson.Writer writer)
        {
            writer.WriteObjectStart();

            // Flows
            writer.WritePropertyStart("flows");
            writer.WriteObjectStart();

            // Multi-flow
            if (_namedFlows != null)
            {
                foreach (var namedFlow in _namedFlows)
                {
                    writer.WriteProperty(namedFlow.Key, namedFlow.Value.WriteJson);
                }
            }

            // Single flow
            else
            {
                writer.WriteProperty(_currentFlow.name, _currentFlow.WriteJson);
            }

            writer.WriteObjectEnd();
            writer.WritePropertyEnd(); // end of flows

            writer.WriteProperty("currentFlowName", _currentFlow.name);

            writer.WriteProperty("variablesState", variablesState.WriteJson);

            writer.WriteProperty("evalStack", w => Json.WriteListRuntimeObjs(w, evaluationStack));


            if (!divertedPointer.isNull)
            {
                writer.WriteProperty("currentDivertTarget", divertedPointer.path.componentsString);
            }

            writer.WriteProperty("visitCounts", w => Json.WriteIntDictionary(w, _visitCounts));
            writer.WriteProperty("turnIndices", w => Json.WriteIntDictionary(w, _turnIndices));


            writer.WriteProperty("turnIdx", currentTurnIndex);
            writer.WriteProperty("storySeed", storySeed);
            writer.WriteProperty("previousRandom", previousRandom);

            writer.WriteProperty("inkSaveVersion", kInkSaveStateVersion);

            // Not using this right now, but could do in future.
            writer.WriteProperty("inkFormatVersion", Story.inkVersionCurrent);

            writer.WriteObjectEnd();
        }
Exemplo n.º 8
0
        void PrintAllMessages()
        {
            // { "issues": ["ERROR: blah", "WARNING: blah"] }
            if (opts.jsonOutput)
            {
                var writer = new Runtime.SimpleJson.Writer();

                writer.WriteObjectStart();
                writer.WritePropertyStart("issues");
                writer.WriteArrayStart();
                foreach (string msg in _authorMessages)
                {
                    writer.Write(msg);
                }
                foreach (string msg in _warnings)
                {
                    writer.Write(msg);
                }
                foreach (string msg in _errors)
                {
                    writer.Write(msg);
                }
                writer.WriteArrayEnd();
                writer.WritePropertyEnd();
                writer.WriteObjectEnd();
                Console.Write(writer.ToString());
            }

            // Human consumption
            else
            {
                PrintIssues(_authorMessages, ConsoleColor.Green);
                PrintIssues(_warnings, ConsoleColor.Blue);
                PrintIssues(_errors, ConsoleColor.Red);
            }

            _authorMessages.Clear();
            _warnings.Clear();
            _errors.Clear();
        }
        void WriteJson(SimpleJson.Writer writer)
        {
            writer.WriteObjectStart();


            bool hasChoiceThreads = false;

            foreach (Choice c in _currentChoices)
            {
                c.originalThreadIndex = c.threadAtGeneration.threadIndex;

                if (callStack.ThreadWithIndex(c.originalThreadIndex) == null)
                {
                    if (!hasChoiceThreads)
                    {
                        hasChoiceThreads = true;
                        writer.WritePropertyStart("choiceThreads");
                        writer.WriteObjectStart();
                    }

                    writer.WritePropertyStart(c.originalThreadIndex);
                    c.threadAtGeneration.WriteJson(writer);
                    writer.WritePropertyEnd();
                }
            }

            if (hasChoiceThreads)
            {
                writer.WriteObjectEnd();
                writer.WritePropertyEnd();
            }

            writer.WriteProperty("callstackThreads", callStack.WriteJson);

            writer.WriteProperty("variablesState", variablesState.WriteJson);

            writer.WriteProperty("evalStack", w => Json.WriteListRuntimeObjs(w, evaluationStack));

            writer.WriteProperty("outputStream", w => Json.WriteListRuntimeObjs(w, _outputStream));

            writer.WriteProperty("currentChoices", w => {
                w.WriteArrayStart();
                foreach (var c in _currentChoices)
                {
                    Json.WriteChoice(w, c);
                }
                w.WriteArrayEnd();
            });

            if (!divertedPointer.isNull)
            {
                writer.WriteProperty("currentDivertTarget", divertedPointer.path.componentsString);
            }

            writer.WriteProperty("visitCounts", w => Json.WriteIntDictionary(w, _visitCounts));
            writer.WriteProperty("turnIndices", w => Json.WriteIntDictionary(w, _turnIndices));


            writer.WriteProperty("turnIdx", currentTurnIndex);
            writer.WriteProperty("storySeed", storySeed);
            writer.WriteProperty("previousRandom", previousRandom);

            writer.WriteProperty("inkSaveVersion", kInkSaveStateVersion);

            // Not using this right now, but could do in future.
            writer.WriteProperty("inkFormatVersion", Story.inkVersionCurrent);

            writer.WriteObjectEnd();
        }
Exemplo n.º 10
0
        public void Begin()
        {
            EvaluateStory();

            var rand = new Random();

            while (story.currentChoices.Count > 0 || this.keepOpenAfterStoryFinish)
            {
                var choices = story.currentChoices;

                var    choiceIdx        = 0;
                bool   choiceIsValid    = false;
                string userDivertedPath = null;

                // autoPlay: Pick random choice
                if (autoPlay)
                {
                    choiceIdx = rand.Next() % choices.Count;
                }

                // Normal: Ask user for choice number
                else
                {
                    if (!_jsonOutput)
                    {
                        Console.ForegroundColor = ConsoleColor.Blue;

                        // Add extra newline to ensure that the choice is
                        // on a separate line.
                        Console.WriteLine();

                        int i = 1;
                        foreach (Choice choice in choices)
                        {
                            Console.WriteLine("{0}: {1}", i, choice.text);
                            i++;
                        }
                    }

                    else
                    {
                        var writer = new Runtime.SimpleJson.Writer();
                        writer.WriteObjectStart();
                        writer.WritePropertyStart("choices");
                        writer.WriteArrayStart();
                        foreach (var choice in choices)
                        {
                            writer.Write(choice.text);
                        }
                        writer.WriteArrayEnd();
                        writer.WritePropertyEnd();
                        writer.WriteObjectEnd();
                        Console.WriteLine(writer.ToString());
                    }


                    do
                    {
                        if (!_jsonOutput)
                        {
                            // Prompt
                            Console.Write("?> ");
                        }

                        else
                        {
                            // Johnny Five, he's alive!
                            Console.Write("{\"needInput\": true}");
                        }

                        string userInput = Console.ReadLine();

                        // If we have null user input, it means that we're
                        // "at the end of the stream", or in other words, the input
                        // stream has closed, so there's nothing more we can do.
                        // We return immediately, since otherwise we get into a busy
                        // loop waiting for user input.
                        if (userInput == null)
                        {
                            if (_jsonOutput)
                            {
                                Console.WriteLine("{\"close\": true}");
                            }
                            else
                            {
                                Console.WriteLine("<User input stream closed.>");
                            }
                            return;
                        }

                        var result = _compiler.ReadCommandLineInput(userInput);

                        if (result.output != null)
                        {
                            if (_jsonOutput)
                            {
                                var writer = new Runtime.SimpleJson.Writer();
                                writer.WriteObjectStart();
                                writer.WriteProperty("cmdOutput", result.output);
                                writer.WriteObjectEnd();
                                Console.WriteLine(writer.ToString());
                            }
                            else
                            {
                                Console.WriteLine(result.output);
                            }
                        }

                        if (result.requestsExit)
                        {
                            return;
                        }

                        if (result.divertedPath != null)
                        {
                            userDivertedPath = result.divertedPath;
                        }

                        if (result.choiceIdx >= 0)
                        {
                            if (result.choiceIdx >= choices.Count)
                            {
                                if (!_jsonOutput)  // fail silently in json mode
                                {
                                    Console.WriteLine("Choice out of range");
                                }
                            }
                            else
                            {
                                choiceIdx     = result.choiceIdx;
                                choiceIsValid = true;
                            }
                        }
                    } while(!choiceIsValid && userDivertedPath == null);
                }

                Console.ResetColor();

                if (choiceIsValid)
                {
                    story.ChooseChoiceIndex(choiceIdx);
                }
                else if (userDivertedPath != null)
                {
                    story.ChoosePathString(userDivertedPath);
                    userDivertedPath = null;
                }

                EvaluateStory();
            }
        }
Exemplo n.º 11
0
        void EvaluateStory()
        {
            while (story.canContinue)
            {
                story.Continue();

                _compiler.RetrieveDebugSourceForLatestContent();

                if (_jsonOutput)
                {
                    var writer = new Runtime.SimpleJson.Writer();
                    writer.WriteObjectStart();
                    writer.WriteProperty("text", story.currentText);
                    writer.WriteObjectEnd();
                    Console.WriteLine(writer.ToString());
                }
                else
                {
                    Console.Write(story.currentText);
                }

                var tags = story.currentTags;
                if (tags.Count > 0)
                {
                    if (_jsonOutput)
                    {
                        var writer = new Runtime.SimpleJson.Writer();
                        writer.WriteObjectStart();
                        writer.WritePropertyStart("tags");
                        writer.WriteArrayStart();
                        foreach (var tag in tags)
                        {
                            writer.Write(tag);
                        }
                        writer.WriteArrayEnd();
                        writer.WritePropertyEnd();
                        writer.WriteObjectEnd();
                        Console.WriteLine(writer.ToString());
                    }
                    else
                    {
                        Console.WriteLine("# tags: " + string.Join(", ", tags));
                    }
                }

                Runtime.SimpleJson.Writer issueWriter = null;
                if (_jsonOutput && (_errors.Count > 0 || _warnings.Count > 0))
                {
                    issueWriter = new Runtime.SimpleJson.Writer();
                    issueWriter.WriteObjectStart();
                    issueWriter.WritePropertyStart("issues");
                    issueWriter.WriteArrayStart();

                    if (_errors.Count > 0)
                    {
                        foreach (var errorMsg in _errors)
                        {
                            issueWriter.Write(errorMsg);
                        }
                    }
                    if (_warnings.Count > 0)
                    {
                        foreach (var warningMsg in _warnings)
                        {
                            issueWriter.Write(warningMsg);
                        }
                    }

                    issueWriter.WriteArrayEnd();
                    issueWriter.WritePropertyEnd();
                    issueWriter.WriteObjectEnd();
                    Console.WriteLine(issueWriter.ToString());
                }

                if (_errors.Count > 0 && !_jsonOutput)
                {
                    foreach (var errorMsg in _errors)
                    {
                        Console.WriteLine(errorMsg, ConsoleColor.Red);
                    }
                }

                if (_warnings.Count > 0 && !_jsonOutput)
                {
                    foreach (var warningMsg in _warnings)
                    {
                        Console.WriteLine(warningMsg, ConsoleColor.Blue);
                    }
                }

                _errors.Clear();
                _warnings.Clear();
            }

            if (story.currentChoices.Count == 0 && keepOpenAfterStoryFinish)
            {
                if (_jsonOutput)
                {
                    Console.WriteLine("{\"end\": true}");
                }
                else
                {
                    Console.WriteLine("--- End of story ---");
                }
            }
        }
Exemplo n.º 12
0
        CommandLineTool(string[] args)
        {
            // Set console's output encoding to UTF-8
            Console.OutputEncoding = System.Text.Encoding.UTF8;

            if (ProcessArguments(args) == false)
            {
                ExitWithUsageInstructions();
            }

            if (opts.inputFile == null)
            {
                ExitWithUsageInstructions();
            }

            string inputString      = null;
            string workingDirectory = Directory.GetCurrentDirectory();

            if (opts.outputFile == null)
            {
                opts.outputFile = Path.ChangeExtension(opts.inputFile, ".ink.json");
            }

            if (!Path.IsPathRooted(opts.outputFile))
            {
                opts.outputFile = Path.Combine(workingDirectory, opts.outputFile);
            }

            try {
                string fullFilename = opts.inputFile;
                if (!Path.IsPathRooted(fullFilename))
                {
                    fullFilename = Path.Combine(workingDirectory, fullFilename);
                }

                // Make the working directory the directory for the root ink file,
                // so that relative paths for INCLUDE files are correct.
                workingDirectory = Path.GetDirectoryName(fullFilename);
                Directory.SetCurrentDirectory(workingDirectory);

                // Now make the input file relative to the working directory,
                // but just getting the file's actual name.
                opts.inputFile = Path.GetFileName(fullFilename);

                inputString = File.ReadAllText(opts.inputFile);
            }
            catch {
                Console.WriteLine("Could not open file '" + opts.inputFile + "'");
                Environment.Exit(ExitCodeError);
            }

            var inputIsJson = opts.inputFile.EndsWith(".json", StringComparison.InvariantCultureIgnoreCase);

            if (inputIsJson && opts.stats)
            {
                Console.WriteLine("Cannot show stats for .json, only for .ink");
                Environment.Exit(ExitCodeError);
            }

            Parsed.Story  parsedStory = null;
            Runtime.Story story       = null;
            Compiler      compiler    = null;

            // Loading a normal ink file (as opposed to an already compiled json file)
            if (!inputIsJson)
            {
                compiler = new Compiler(inputString, new Compiler.Options {
                    sourceFilename    = opts.inputFile,
                    pluginDirectories = pluginDirectories,
                    countAllVisits    = opts.countAllVisits,
                    errorHandler      = OnError
                });

                // Only want stats, don't need to code-gen
                if (opts.stats)
                {
                    parsedStory = compiler.Parse();

                    // Print any errors
                    PrintAllMessages();

                    // Generate stats, then print as JSON
                    var stats = Ink.Stats.Generate(compiler.parsedStory);

                    if (opts.jsonOutput)
                    {
                        var writer = new Runtime.SimpleJson.Writer();

                        writer.WriteObjectStart();
                        writer.WritePropertyStart("stats");

                        writer.WriteObjectStart();
                        writer.WriteProperty("words", stats.words);
                        writer.WriteProperty("knots", stats.knots);
                        writer.WriteProperty("stitches", stats.stitches);
                        writer.WriteProperty("functions", stats.functions);
                        writer.WriteProperty("choices", stats.choices);
                        writer.WriteProperty("gathers", stats.gathers);
                        writer.WriteProperty("diverts", stats.diverts);
                        writer.WriteObjectEnd();

                        writer.WritePropertyEnd();
                        writer.WriteObjectEnd();

                        Console.WriteLine(writer.ToString());
                    }
                    else
                    {
                        Console.WriteLine("Words: " + stats.words);
                        Console.WriteLine("Knots: " + stats.knots);
                        Console.WriteLine("Stitches: " + stats.stitches);
                        Console.WriteLine("Functions: " + stats.functions);
                        Console.WriteLine("Choices: " + stats.choices);
                        Console.WriteLine("Gathers: " + stats.gathers);
                        Console.WriteLine("Diverts: " + stats.diverts);
                    }

                    return;
                }

                // Full compile
                else
                {
                    story = compiler.Compile();
                }
            }

            // Opening up a compiled json file for playing
            else
            {
                story = new Runtime.Story(inputString);

                // No purpose for loading an already compiled file other than to play it
                opts.playMode = true;
            }

            var compileSuccess = !(story == null || _errors.Count > 0);

            if (opts.jsonOutput)
            {
                if (compileSuccess)
                {
                    Console.WriteLine("{\"compile-success\": true}");
                }
                else
                {
                    Console.WriteLine("{\"compile-success\": false}");
                }
            }


            PrintAllMessages();

            if (!compileSuccess)
            {
                Environment.Exit(ExitCodeError);
            }

            // Play mode
            if (opts.playMode)
            {
                _playing = true;

                // Always allow ink external fallbacks
                story.allowExternalFunctionFallbacks = true;

                var player = new CommandLinePlayer(story, false, compiler, opts.keepOpenAfterStoryFinish, opts.jsonOutput);

                //Capture a CTRL+C key combo so we can restore the console's foreground color back to normal when exiting
                Console.CancelKeyPress += OnExit;

                try {
                    player.Begin();
                } catch (Runtime.StoryException e) {
                    if (e.Message.Contains("Missing function binding"))
                    {
                        OnError(e.Message, ErrorType.Error);
                        PrintAllMessages();
                    }
                    else
                    {
                        throw e;
                    }
                } catch (System.Exception e) {
                    string storyPath = "<END>";
                    var    path      = story.state.currentPathString;
                    if (path != null)
                    {
                        storyPath = path.ToString();
                    }
                    throw new System.Exception(e.Message + " (Internal story path: " + storyPath + ")", e);
                }
            }

            // Compile mode
            else
            {
                var jsonStr = story.ToJson();

                try {
                    File.WriteAllText(opts.outputFile, jsonStr, new System.Text.UTF8Encoding(false));

                    if (opts.jsonOutput)
                    {
                        Console.WriteLine("{\"export-complete\": true}");
                    }
                } catch {
                    Console.WriteLine("Could not write to output file '" + opts.outputFile + "'");
                    Environment.Exit(ExitCodeError);
                }
            }
        }
Exemplo n.º 13
0
        public string RequestExternalFunctionResult(string functionName, object[] args)
        {
            var arguments = "";

            for (var i = 0; i < args.Length; i++)
            {
                if (args[i] is string)
                {
                    args[i] = "\"" + args[i] + "\"";
                }
                arguments += args[i];
                if (i + 1 < args.Length)
                {
                    arguments += ", ";
                }
            }

            if (!_jsonOutput)
            {
                Console.ForegroundColor = ConsoleColor.Blue;
                Console.Write("Enter result for " + functionName + "(" + arguments + ") > ");
                Console.ResetColor();
            }
            else
            {
                var writer = new Runtime.SimpleJson.Writer();
                writer.WriteObjectStart();
                writer.WriteProperty("external-function", functionName);
                if (arguments != "")
                {
                    writer.WritePropertyStart("arguments");
                    writer.WriteArrayStart();
                    writer.Write(arguments);
                    writer.WriteArrayEnd();
                    writer.WritePropertyEnd();
                }
                writer.WriteObjectEnd();
                Console.WriteLine(writer.ToString());
            }

            string userInput = Console.ReadLine();

            // If we have null user input, it means that we're
            // "at the end of the stream", or in other words, the input
            // stream has closed, so there's nothing more we can do.
            // We return immediately, since otherwise we get into a busy
            // loop waiting for user input.
            if (userInput == null)
            {
                if (_jsonOutput)
                {
                    Console.WriteLine("{\"close\": true}");
                }
                else
                {
                    Console.WriteLine("<User input stream closed.>");
                }
            }

            return(userInput);
        }