API Basic Config ko - LIHACHTETAN/ClassicUO-BadNewbie-BasicIDE GitHub Wiki

JSON / Config.bas

ClassicUO โ€ข Basic

Config.bas๋Š” Scripts/Include์— ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฉ”์ธ ์Šคํฌ๋ฆฝํŠธ ์˜†์— Include/Config.bas๋ฅผ ๋‘๊ณ  Include "Config.bas"๋ฅผ ์ ์Šต๋‹ˆ๋‹ค. ์˜๊ตฌ JSON๊ณผ ๋…๋ฆฝ์ ์ธ ๊ธฐ๋ณธ๊ฐ’์„ ๊ฒฐํ•ฉํ•ฉ๋‹ˆ๋‹ค.

์ •ํ™•ํ•œ ๊ตฌ๋ฌธ

Include "Config.bas"
settings = Config.Load(fileName, defaults)
Config.Save(fileName, settings)
enabled = Config.GetFlag(settings, key, fallback=False)
Config.SetFlag(settings, key, value)
JsonParse(text) / JsonStringify(value[, indented=0])
JsonLoad(fileName[, defaultValue]) / JsonSave(fileName, value[, indented=1])
JsonKind(value) / JsonBoolean(value) / JsonNull() / flag.Value()

๋งค๊ฐœ๋ณ€์ˆ˜

  • fileName โ€” ํ•„์ˆ˜ ํŒŒ์ผ ๊ฒฝ๋กœ. ์ƒ๋Œ€ ๊ฒฝ๋กœ๋Š” Include์—์„œ ํ˜ธ์ถœํ•ด๋„ ๋ฉ”์ธ ์Šคํฌ๋ฆฝํŠธ ํด๋” ๊ธฐ์ค€์ž…๋‹ˆ๋‹ค. ์ ˆ๋Œ€ ๊ฒฝ๋กœ๋„ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • defaults (Config.Load) โ€” Config.Load์— ํ•„์ˆ˜์ธ ๊ธฐ๋ณธ๊ฐ’ Dictionary์ž…๋‹ˆ๋‹ค. ๊นŠ์€ JSON ๋ณต์‚ฌ๋ณธ์— ์ €์žฅ๋œ ์ตœ์ƒ์œ„ ํ‚ค๋ฅผ ๋ณ‘ํ•ฉํ•˜๋ฉฐ ์›๋ณธ์„ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. defaults๋ฅผ ์ƒ๋žตํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  • defaultValue (JsonLoad) โ€” ํŒŒ์ผ์ด๋‚˜ ํด๋”๊ฐ€ ์—†์„ ๋•Œ๋งŒ ์‚ฌ์šฉํ•˜๋Š” ์„ ํƒ์  ๋Œ€์ฒด ๊ฐ’. JSON ๋ณ€ํ™˜์„ ํ†ตํ•œ ๋…๋ฆฝ ๋ณต์‚ฌ๋ณธ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋‚ด์šฉ, ์ธ์ฝ”๋”ฉ ๋ฐ ์ ‘๊ทผ ์˜ค๋ฅ˜๋ฅผ ์ˆจ๊ธฐ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • settings / value โ€” ์ˆซ์ž, String, ๋ฐฐ์—ด, List, Dictionary, JsonBoolean ๋˜๋Š” JsonNull. Dictionary ํ‚ค๋Š” String์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ฐธ์กฐ ๊ณต์œ ๋Š” ํ—ˆ์šฉํ•˜์ง€๋งŒ ์ˆœํ™˜ ์ฐธ์กฐ๋Š” ์˜ค๋ฅ˜์ž…๋‹ˆ๋‹ค.
  • indented โ€” Integer ํ”Œ๋ž˜๊ทธ:0์€ ์••์ถ• ํ˜•์‹, 0์ด ์•„๋‹ˆ๋ฉด ๋“ค์—ฌ์“ฐ๊ธฐ. ๊ธฐ๋ณธ๊ฐ’:Stringify=0, Save=1.
  • key / fallback โ€” Config.Load(fileName, defaults)๋Š” ์ƒˆ Dictionary๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ €์žฅ๋œ ์ตœ์ƒ์œ„ ํ‚ค๊ฐ€ defaults์˜ ๊นŠ์€ ๋ณต์‚ฌ๋ณธ์„ ๋ฎ์–ด์“ฐ๊ณ  ์ค‘์ฒฉ ๊ฐ์ฒด๋Š” ํ†ต์งธ๋กœ ๊ต์ฒดํ•ฉ๋‹ˆ๋‹ค. Config.Save(fileName, settings)๋Š” ๋ช…์‹œ์ ์œผ๋กœ ์ €์žฅํ•˜๋ฉฐ ๋ฐ˜ํ™˜๊ฐ’์ด ์—†์Šต๋‹ˆ๋‹ค. Config.GetFlag(settings, key, fallback=False)๋Š”1/True ๋˜๋Š”0/False๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ ๊ธฐ์กด ๊ฐ’์ด ๋ถˆ๋ฆฌ์–ธ์ด ์•„๋‹ˆ๋ฉด ์˜ค๋ฅ˜์ž…๋‹ˆ๋‹ค. Config.SetFlag(settings, key, value)๋Š” ๋ฉ”๋ชจ๋ฆฌ๋งŒ ๋ณ€๊ฒฝํ•˜๊ณ  ๋ฐ˜ํ™˜๊ฐ’์ด ์—†์Šต๋‹ˆ๋‹ค. Load/Save๋Š” String ํ‚ค Dictionary๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๋‚ด๋ถ€ Private RequireObject๋Š” ๋ฐ”๊นฅ ์ข…๋ฅ˜๋ฅผ ํ™•์ธํ•˜๊ณ  JSON ๋ณ€ํ™˜์€ ์ „์ฒด ๋‚ด์šฉ์„ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค.

๋ฐ˜ํ™˜๊ฐ’

Config.Load(fileName, defaults)๋Š” ์ƒˆ Dictionary๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ €์žฅ๋œ ์ตœ์ƒ์œ„ ํ‚ค๊ฐ€ defaults์˜ ๊นŠ์€ ๋ณต์‚ฌ๋ณธ์„ ๋ฎ์–ด์“ฐ๊ณ  ์ค‘์ฒฉ ๊ฐ์ฒด๋Š” ํ†ต์งธ๋กœ ๊ต์ฒดํ•ฉ๋‹ˆ๋‹ค. Config.Save(fileName, settings)๋Š” ๋ช…์‹œ์ ์œผ๋กœ ์ €์žฅํ•˜๋ฉฐ ๋ฐ˜ํ™˜๊ฐ’์ด ์—†์Šต๋‹ˆ๋‹ค. Config.GetFlag(settings, key, fallback=False)๋Š”1/True ๋˜๋Š”0/False๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ ๊ธฐ์กด ๊ฐ’์ด ๋ถˆ๋ฆฌ์–ธ์ด ์•„๋‹ˆ๋ฉด ์˜ค๋ฅ˜์ž…๋‹ˆ๋‹ค. Config.SetFlag(settings, key, value)๋Š” ๋ฉ”๋ชจ๋ฆฌ๋งŒ ๋ณ€๊ฒฝํ•˜๊ณ  ๋ฐ˜ํ™˜๊ฐ’์ด ์—†์Šต๋‹ˆ๋‹ค. Load/Save๋Š” String ํ‚ค Dictionary๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๋‚ด๋ถ€ Private RequireObject๋Š” ๋ฐ”๊นฅ ์ข…๋ฅ˜๋ฅผ ํ™•์ธํ•˜๊ณ  JSON ๋ณ€ํ™˜์€ ์ „์ฒด ๋‚ด์šฉ์„ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค.

๋™์ž‘

  • UO. ์—†๋Š” ๋กœ์ปฌ Basic ํ•จ์ˆ˜์ด๋ฉฐ ๊ฒŒ์ž„ ํŒจํ‚ท์„ ๋ณด๋‚ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. JsonParse/JsonStringify๋Š” ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. Basic True๋Š” ์ˆซ์ž1๋กœ ์ €์žฅ๋˜๋ฏ€๋กœ JSON true์—๋Š” JsonBoolean(True)๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. JsonNull()์€ null๊ณผ0์„ ๊ตฌ๋ถ„ํ•ฉ๋‹ˆ๋‹ค.
  • ์œ ํ•œํ•œ ์ˆซ์ž๋งŒ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ •์ˆ˜ ๊ฐ’์ด ยฑ9007199254740991 ๋ฒ”์œ„๋ฅผ ๋„˜์œผ๋ฉด ์˜ค๋ฅ˜์ด๋ฉฐ ํฐ ID๋Š” String์œผ๋กœ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์ˆซ์ž๋Š” Double ์ •๋ฐ€๋„์ž…๋‹ˆ๋‹ค. ์—„๊ฒฉํ•œ UTF-8์„ ์‚ฌ์šฉํ•˜๋ฉฐ ์ž…๋ ฅ BOM์€ ํ—ˆ์šฉํ•˜๊ณ  ์ถœ๋ ฅ์—๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์ž˜๋ชป๋œ Unicode๋Š” ์˜ค๋ฅ˜์ž…๋‹ˆ๋‹ค.
  • ์ œํ•œ:1048576 UTF-16 ์ฝ”๋“œ ๋‹จ์œ„,4MiB,64๋‹จ๊ณ„ ์ปจํ…Œ์ด๋„ˆ,100000 ๊ฐ’ ๋…ธ๋“œ. ์ดˆ๊ณผํ•˜๋ฉด ์˜ค๋ฅ˜์ž…๋‹ˆ๋‹ค. ๋ถ„์„/์ฝ๊ธฐ๋Š” ์ƒˆ ์ปฌ๋ ‰์…˜์„ ๋งŒ๋“ค๋ฉฐ ์ €์žฅ์€ ๋ฉ”๋ชจ๋ฆฌ ๊ฐ์ฒด๋ฅผ ๋ณต์ œํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • Save๋Š” ์ „์ฒด ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒ€์ฆํ•˜๊ณ  ๋ถ€๋ชจ ํด๋”๋ฅผ ๋งŒ๋“  ๋’ค ๋Œ€์ƒ ์˜†์˜ ๊ณ ์œ  ์ž„์‹œ ํŒŒ์ผ์— ์“ฐ๊ณ  ๋ฒ„ํผ๋ฅผ ๋น„์šด ํ›„ ์ด๋™/๊ต์ฒดํ•ฉ๋‹ˆ๋‹ค. ๊ต์ฒด ์ „ ์‹คํŒจ/์ทจ์†Œ๋Š” ๊ธฐ์กด ํŒŒ์ผ์„ ๋ณด์กดํ•ฉ๋‹ˆ๋‹ค. OS๊ฐ€ ํ—ˆ์šฉํ•˜๋ฉด ์ž„์‹œ ํŒŒ์ผ์„ ์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์™„๋ฃŒ๋œ ๊ต์ฒด๋Š” ์ทจ์†Œํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • 256๊ฐœ ๊ฐ’๋งˆ๋‹ค,4096๋ฐ”์ดํŠธ/๋ฌธ์ž ๋ธ”๋ก ์‚ฌ์ด ๋ฐ ๊ต์ฒด ์ „์— ์ผ์‹œ์ •์ง€/์ค‘์ง€๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ์ถ”๊ฐ€ ์Šค๋ ˆ๋“œ๋ฅผ ๋งŒ๋“ค์ง€ ์•Š์œผ๋ฉฐ ๊ฐœ๋ณ„ OS ํ˜ธ์ถœ์€ ๊ฐ•์ œ ์ค‘๋‹จํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋™์‹œ ์ €์žฅ์€ ๋งˆ์ง€๋ง‰ ์„ฑ๊ณต ๊ต์ฒด๊ฐ€ ๋‚จ์œผ๋ฉฐ DB ํŠธ๋žœ์žญ์…˜์ด ์•„๋‹™๋‹ˆ๋‹ค.

์˜ˆ์ œ

1. ๋…๋ฆฝ์ ์ธ ๊ธฐ๋ณธ๊ฐ’

# fileName=missing-settings.json์ด๋ฉฐ defaults์— delay=350์ด ์žˆ์Šต๋‹ˆ๋‹ค. ํŒŒ์ผ์ด ์—†์œผ๋ฉด Load๊ฐ€ defaults๋ฅผ ๋ณต์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ๋ฅผ125๋กœ ๋ฐ”๊ฟ”๋„ ๊ธฐ์กด350์€ ์œ ์ง€๋˜์–ด ๊ฒฐ๊ณผ๋Š”"125:350"์ž…๋‹ˆ๋‹ค. ํŒŒ์ผ ๋ถ€์žฌ๋ฅผ ์‹œํ—˜ํ•˜๊ธฐ ์ „์— ์ด์ „ ์˜ˆ์ œ ํŒŒ์ผ์„ ์˜ฎ๊ธฐ๊ฑฐ๋‚˜ ์‚ญ์ œํ•˜์„ธ์š”.
Option Explicit On
Include "Config.bas"
Sub Main()
    Dim defaults=Dictionary()
    defaults["delay"]=350
    Dim settings=Config.Load("missing-settings.json", defaults)
    settings["delay"]=125
    Return CStr(settings["delay"]) & ":" & CStr(defaults["delay"])
End Sub

๋งค๊ฐœ๋ณ€์ˆ˜ ๋ฐ ์‹คํ–‰ ์„ค๋ช…:

fileName=missing-settings.json์ด๋ฉฐ defaults์— delay=350์ด ์žˆ์Šต๋‹ˆ๋‹ค. ํŒŒ์ผ์ด ์—†์œผ๋ฉด Load๊ฐ€ defaults๋ฅผ ๋ณต์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ๋ฅผ125๋กœ ๋ฐ”๊ฟ”๋„ ๊ธฐ์กด350์€ ์œ ์ง€๋˜์–ด ๊ฒฐ๊ณผ๋Š”"125:350"์ž…๋‹ˆ๋‹ค. ํŒŒ์ผ ๋ถ€์žฌ๋ฅผ ์‹œํ—˜ํ•˜๊ธฐ ์ „์— ์ด์ „ ์˜ˆ์ œ ํŒŒ์ผ์„ ์˜ฎ๊ธฐ๊ฑฐ๋‚˜ ์‚ญ์ œํ•˜์„ธ์š”.

Include/Config.bas

Option Explicit On

' Copy Include/Config.bas beside your main script, then Include "Config.bas".
' Relative JSON paths are based on the main script's folder, not this module.
Module Config
    Private Sub RequireObject(ByVal value)
        If JsonKind(value) <> "object" Then
            Throw "Config requires a Dictionary with string keys."
        End If
    End Sub

    ' Returns a new Dictionary. Saved top-level keys override independent defaults.
    ' Missing files use defaults; invalid files raise an error and remain unchanged.
    Public Function Load(ByVal fileName, ByVal defaults)
        RequireObject(defaults)
        Dim result = JsonParse(JsonStringify(defaults))
        Dim saved = JsonLoad(fileName, Dictionary())
        RequireObject(saved)
        For Each entry In saved
            result.Set(entry.Key(), entry.Value())
        Next
        Return result
    End Function

    ' No return value. Validates and writes UTF-8 using same-directory replacement.
    Public Sub Save(ByVal fileName, ByVal settings)
        RequireObject(settings)
        JsonSave(fileName, settings)
    End Sub

    ' A JSON Boolean is distinct from a Basic numeric flag. Convert explicitly.
    ' Returns 1/True or 0/False; non-Boolean saved values raise an error.
    Public Function GetFlag(ByVal settings, ByVal key, Optional ByVal fallback=False)
        RequireObject(settings)
        Dim flag = settings.Get(key, JsonBoolean(fallback))
        If JsonKind(flag) <> "boolean" Then
            Throw "Config.GetFlag expects a JSON Boolean for key: " & CStr(key)
        End If
        Return flag.Value()
    End Function

    ' Changes the Dictionary in memory; call Save to persist it.
    Public Sub SetFlag(ByVal settings, ByVal key, ByVal value)
        RequireObject(settings)
        settings.Set(key, JsonBoolean(value))
    End Sub
End Module

2. ์ €์žฅ ํ›„ ๋‹ค์‹œ ์ฝ๊ธฐ

# SetFlag๊ฐ€ JSON ๋ถˆ๋ฆฌ์–ธ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค. Save๊ฐ€ demo-settings.json์„ ์ƒ์„ฑ/๊ต์ฒดํ•˜๊ณ  Load๊ฐ€ ์ฝ์Šต๋‹ˆ๋‹ค. GetFlag๋Š” Integer1, delay=350์ด๋ฏ€๋กœ ๊ฒฐ๊ณผ๋Š”"1:350"์ž…๋‹ˆ๋‹ค.
Option Explicit On
Include "Config.bas"
Sub Main()
    Dim settings=Dictionary()
    settings["delay"]=350
    Config.SetFlag(settings, "enabled", True)
    Config.Save("demo-settings.json", settings)
    Dim loaded=Config.Load("demo-settings.json", Dictionary())
    Return CStr(Config.GetFlag(loaded, "enabled")) & ":" & CStr(loaded["delay"])
End Sub

๋งค๊ฐœ๋ณ€์ˆ˜ ๋ฐ ์‹คํ–‰ ์„ค๋ช…:

SetFlag๊ฐ€ JSON ๋ถˆ๋ฆฌ์–ธ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค. Save๊ฐ€ demo-settings.json์„ ์ƒ์„ฑ/๊ต์ฒดํ•˜๊ณ  Load๊ฐ€ ์ฝ์Šต๋‹ˆ๋‹ค. GetFlag๋Š” Integer1, delay=350์ด๋ฏ€๋กœ ๊ฒฐ๊ณผ๋Š”"1:350"์ž…๋‹ˆ๋‹ค.

Include/Config.bas

Option Explicit On

' Copy Include/Config.bas beside your main script, then Include "Config.bas".
' Relative JSON paths are based on the main script's folder, not this module.
Module Config
    Private Sub RequireObject(ByVal value)
        If JsonKind(value) <> "object" Then
            Throw "Config requires a Dictionary with string keys."
        End If
    End Sub

    ' Returns a new Dictionary. Saved top-level keys override independent defaults.
    ' Missing files use defaults; invalid files raise an error and remain unchanged.
    Public Function Load(ByVal fileName, ByVal defaults)
        RequireObject(defaults)
        Dim result = JsonParse(JsonStringify(defaults))
        Dim saved = JsonLoad(fileName, Dictionary())
        RequireObject(saved)
        For Each entry In saved
            result.Set(entry.Key(), entry.Value())
        Next
        Return result
    End Function

    ' No return value. Validates and writes UTF-8 using same-directory replacement.
    Public Sub Save(ByVal fileName, ByVal settings)
        RequireObject(settings)
        JsonSave(fileName, settings)
    End Sub

    ' A JSON Boolean is distinct from a Basic numeric flag. Convert explicitly.
    ' Returns 1/True or 0/False; non-Boolean saved values raise an error.
    Public Function GetFlag(ByVal settings, ByVal key, Optional ByVal fallback=False)
        RequireObject(settings)
        Dim flag = settings.Get(key, JsonBoolean(fallback))
        If JsonKind(flag) <> "boolean" Then
            Throw "Config.GetFlag expects a JSON Boolean for key: " & CStr(key)
        End If
        Return flag.Value()
    End Function

    ' Changes the Dictionary in memory; call Save to persist it.
    Public Sub SetFlag(ByVal settings, ByVal key, ByVal value)
        RequireObject(settings)
        settings.Set(key, JsonBoolean(value))
    End Sub
End Module

3. ํ”Œ๋ž˜๊ทธ ํƒ€์ž… ํ™•์ธ

# enabled=1์€ ์ˆซ์ž์ด๋ฉฐ JSON true๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. GetFlag๊ฐ€ ๊ฑฐ๋ถ€ํ•˜๊ณ  Catch๋Š”"invalid flag"๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. SetFlag(settings,"enabled",True)๋Š” ์˜ฌ๋ฐ”๋ฅธ ํƒ€์ž…์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ํŒŒ์ผ์€ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
Option Explicit On
Include "Config.bas"
Sub Main()
    Dim settings=Dictionary()
    settings["enabled"]=1
    Try
        Dim enabled=Config.GetFlag(settings, "enabled")
    Catch problem
        Return "invalid flag"
    End Try
    Return "unexpected"
End Sub

๋งค๊ฐœ๋ณ€์ˆ˜ ๋ฐ ์‹คํ–‰ ์„ค๋ช…:

enabled=1์€ ์ˆซ์ž์ด๋ฉฐ JSON true๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. GetFlag๊ฐ€ ๊ฑฐ๋ถ€ํ•˜๊ณ  Catch๋Š”"invalid flag"๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. SetFlag(settings,"enabled",True)๋Š” ์˜ฌ๋ฐ”๋ฅธ ํƒ€์ž…์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ํŒŒ์ผ์€ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

Include/Config.bas

Option Explicit On

' Copy Include/Config.bas beside your main script, then Include "Config.bas".
' Relative JSON paths are based on the main script's folder, not this module.
Module Config
    Private Sub RequireObject(ByVal value)
        If JsonKind(value) <> "object" Then
            Throw "Config requires a Dictionary with string keys."
        End If
    End Sub

    ' Returns a new Dictionary. Saved top-level keys override independent defaults.
    ' Missing files use defaults; invalid files raise an error and remain unchanged.
    Public Function Load(ByVal fileName, ByVal defaults)
        RequireObject(defaults)
        Dim result = JsonParse(JsonStringify(defaults))
        Dim saved = JsonLoad(fileName, Dictionary())
        RequireObject(saved)
        For Each entry In saved
            result.Set(entry.Key(), entry.Value())
        Next
        Return result
    End Function

    ' No return value. Validates and writes UTF-8 using same-directory replacement.
    Public Sub Save(ByVal fileName, ByVal settings)
        RequireObject(settings)
        JsonSave(fileName, settings)
    End Sub

    ' A JSON Boolean is distinct from a Basic numeric flag. Convert explicitly.
    ' Returns 1/True or 0/False; non-Boolean saved values raise an error.
    Public Function GetFlag(ByVal settings, ByVal key, Optional ByVal fallback=False)
        RequireObject(settings)
        Dim flag = settings.Get(key, JsonBoolean(fallback))
        If JsonKind(flag) <> "boolean" Then
            Throw "Config.GetFlag expects a JSON Boolean for key: " & CStr(key)
        End If
        Return flag.Value()
    End Function

    ' Changes the Dictionary in memory; call Save to persist it.
    Public Sub SetFlag(ByVal settings, ByVal key, ByVal value)
        RequireObject(settings)
        settings.Set(key, JsonBoolean(value))
    End Sub
End Module

en ยท ru ยท uk ยท fr ยท de ยท it ยท es ยท zh-tw ยท ja ยท ko

Basic