From 4f989aa51242d769c23955eb6affec2c80e047dc Mon Sep 17 00:00:00 2001 From: "Radu Macocian (admac)" Date: Fri, 12 Jun 2026 16:44:04 +0200 Subject: [PATCH] added structure for db --- config/config.go | 19 +++++++++++ db/history/history.go | 65 +++++++++++++++++++++++++++++++++++++ go.mod | 11 +++++++ go.sum | 74 +++++++++++++++++++++++++++++++++++++++++++ llm/client.go | 49 ++++++++++------------------ model/Message.go | 14 ++++++++ ui/chat.go | 38 +++++++++++++--------- ui/landing.go | 40 ++++++++++++++++------- 8 files changed, 252 insertions(+), 58 deletions(-) create mode 100644 db/history/history.go create mode 100644 model/Message.go diff --git a/config/config.go b/config/config.go index 4443619..5ebced9 100644 --- a/config/config.go +++ b/config/config.go @@ -14,6 +14,25 @@ type Config struct { Api ApiConfig Llm LLMConfig Logging []LogConfig + Db DbConfig +} + +type DbConfig struct { + Url string + Port string + DbName string + User string + Password string + History HistoryConfig + Memory MemoryConfig +} + +type MemoryConfig struct { + Enabled bool +} + +type HistoryConfig struct { + Enabled bool } type ApiConfig struct { diff --git a/db/history/history.go b/db/history/history.go new file mode 100644 index 0000000..9870e24 --- /dev/null +++ b/db/history/history.go @@ -0,0 +1,65 @@ +package history + +import ( + "net" + "net/url" + + "git.estatecloud.org/radumaco/souvenir/config" + "git.estatecloud.org/radumaco/souvenir/model" + "github.com/gopsql/pgx" +) + +type DbClient struct { + Cfg config.DbConfig +} + +type Conversation struct { + Id string + Messages []model.Message +} + +func (client DbClient) init() error { + const createConversationTable = ` + CREATE TABLE IF NOT EXISTS conversations ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + created_at TIMESTAMPTZ NOT NULL DEFAULT now() + )` + const createMessageTable = ` + CREATE TABLE IF NOT EXISTS messages ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + role TEXT NOT NULL + content TEXT NOT NULL + conversation_id UUID + created_at TIMESTAMPTZ NOT NULL DEFAULT now() + )` + const createToolCallTable = ` + CREATE TABLE IF NOT EXISTS tool_calls ( + id UUID PRIMARY KEY, + type TEXT NOT NULL + functionName TEXT NOT NULL + functionArgs TEXT NOT NULL + message_id UUID + created_at TIMESTAMPTZ NOT NULL DEFAULT now() + )` + + conn := pgx.MustOpen(client.connectionString()) + defer conn.Close() + + if _, err := conn.Exec(createToolCallTable); err != nil { + return err + } + if _, err := conn.Exec(createToolCallTable); err != nil { + return err + } + return nil +} + +func (client DbClient) connectionString() string { + u := &url.URL{ + Scheme: "postgres", + User: url.UserPassword(client.Cfg.User, client.Cfg.Password), + Host: net.JoinHostPort(client.Cfg.Url, client.Cfg.Port), + Path: client.Cfg.DbName, + } + return u.String() +} diff --git a/go.mod b/go.mod index 9116d53..f941808 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,16 @@ require ( charm.land/lipgloss/v2 v2.0.3 ) +require ( + github.com/gopsql/db v1.2.1 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect + github.com/jackc/pgx/v5 v5.4.3 // indirect + github.com/jackc/puddle/v2 v2.2.1 // indirect + golang.org/x/crypto v0.9.0 // indirect + golang.org/x/text v0.9.0 // indirect +) + require ( github.com/atotto/clipboard v0.1.4 // indirect github.com/charmbracelet/colorprofile v0.4.3 // indirect @@ -18,6 +28,7 @@ require ( github.com/charmbracelet/x/windows v0.2.2 // indirect github.com/clipperhouse/displaywidth v0.11.0 // indirect github.com/clipperhouse/uax29/v2 v2.7.0 // indirect + github.com/gopsql/pgx v1.5.0 github.com/lucasb-eyer/go-colorful v1.4.0 // indirect github.com/mattn/go-runewidth v0.0.23 // indirect github.com/muesli/cancelreader v0.2.2 // indirect diff --git a/go.sum b/go.sum index 41d49a9..cbecd21 100644 --- a/go.sum +++ b/go.sum @@ -28,19 +28,93 @@ github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSE github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0= github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gopsql/db v1.2.1 h1:dzi13FK9OCeV2pARpmn4kSp351Uzg/Le2mEKo43H+EQ= +github.com/gopsql/db v1.2.1/go.mod h1:plazrQDxoOfbv749q6AqZyR0wtPak19s4uw8J8pnMYA= +github.com/gopsql/pgx v1.5.0 h1:0kuDwjS2lCFTWUe8w0mBXM6JCTGKCwtPg3zEtDH0Lpw= +github.com/gopsql/pgx v1.5.0/go.mod h1:F95IVkBjVotZIiN8UtSdZBe111alDqRaOERaLQeY9pg= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY= +github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA= +github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= +github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lucasb-eyer/go-colorful v1.4.0 h1:UtrWVfLdarDgc44HcS7pYloGHJUjHV/4FwW4TvVgFr4= github.com/lucasb-eyer/go-colorful v1.4.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/mattn/go-runewidth v0.0.23 h1:7ykA0T0jkPpzSvMS5i9uoNn2Xy3R383f9HDx3RybWcw= github.com/mattn/go-runewidth v0.0.23/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/llm/client.go b/llm/client.go index 16da60d..5adfe12 100644 --- a/llm/client.go +++ b/llm/client.go @@ -10,6 +10,7 @@ import ( "strconv" config "git.estatecloud.org/radumaco/souvenir/config" + "git.estatecloud.org/radumaco/souvenir/model" ) type LLMClient struct { @@ -19,15 +20,9 @@ type LLMClient struct { // Request Types type ChatRequest struct { - Model string `json:"model"` - Messages []Message `json:"messages"` - Tools []config.Tool `json:"tools,omitempty"` -} - -type Message struct { - Role string `json:"role"` - Content string `json:"content"` - ToolCalls []ToolCall `json:"tool_calls,omitempty"` + Model string `json:"model"` + Messages []model.Message `json:"messages"` + Tools []config.Tool `json:"tools,omitempty"` } // Response types // @@ -42,20 +37,9 @@ type ChatResponse struct { } type Choice struct { - Index int `json:"index"` - Message Message `json:"message"` - FinishReason string `json:"finish_reason"` -} - -type ToolCall struct { - ID string `json:"id"` - Type string `json:"type"` - Function ToolCallFunc `json:"function"` -} - -type ToolCallFunc struct { - Name string `json:"name"` - Arguments string `json:"arguments"` + Index int `json:"index"` + Message model.Message `json:"message"` + FinishReason string `json:"finish_reason"` } type Usage struct { @@ -64,7 +48,8 @@ type Usage struct { TotalTokens int `json:"total_tokens"` } -func (client LLMClient) Call(query string, messages []Message) ([]Message, error) { +func (client LLMClient) Call(query string, messages []model.Message) ([]model.Message, error) { + return []model.Message{{Role: "assistant", Content: "message 1"}, {Role: "assistant", Content: "message 2"}}, nil var logger = slog.Default().With("Component", "LLM Client") requestBody := ChatRequest{ Model: client.Cfg.Llm.Model, @@ -73,7 +58,7 @@ func (client LLMClient) Call(query string, messages []Message) ([]Message, error } serialized, err := json.Marshal(requestBody) if err != nil { - return []Message{}, err + return []model.Message{}, err } body := bytes.NewBuffer(serialized) @@ -81,14 +66,14 @@ func (client LLMClient) Call(query string, messages []Message) ([]Message, error req, err := http.NewRequest("POST", client.Cfg.Api.Url, body) if err != nil { logger.Error("There was an error creating the request", "error", err.Error()) - return []Message{}, err + return []model.Message{}, err } req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "Bearer "+client.Cfg.Api.Key) resp, err := http.DefaultClient.Do(req) if err != nil { logger.Error("There was an error during http call", "error", err.Error()) - return []Message{}, err + return []model.Message{}, err } logger.Debug("LLM Call returned", "response", resp) defer resp.Body.Close() @@ -96,13 +81,13 @@ func (client LLMClient) Call(query string, messages []Message) ([]Message, error data, err := io.ReadAll(resp.Body) if err != nil { logger.Error("There was an error reading the response body", "error", err.Error()) - return []Message{}, err + return []model.Message{}, err } if resp.StatusCode != 200 && resp.StatusCode != 202 { logger.Error("Call returned non 200 status", "statusCode", resp.StatusCode, "status", resp.Status) - return []Message{}, + return []model.Message{}, errors.New("Call returned invalid status " + strconv.Itoa(resp.StatusCode) + resp.Status) @@ -112,13 +97,13 @@ func (client LLMClient) Call(query string, messages []Message) ([]Message, error var response ChatResponse if err := json.Unmarshal(data, &response); err != nil { logger.Error("There was an error parsing the response", "error", err.Error()) - return []Message{}, err + return []model.Message{}, err } - var result []Message + var result []model.Message if len(response.Choices) == 0 { logger.Error("The call returned an empty response") - return []Message{}, errors.New("The call returned an empty response") + return []model.Message{}, errors.New("The call returned an empty response") } for _, choice := range response.Choices { logger.Error("Appending response message", "message", choice.Message) diff --git a/model/Message.go b/model/Message.go new file mode 100644 index 0000000..5afa771 --- /dev/null +++ b/model/Message.go @@ -0,0 +1,14 @@ +package model + +type Message struct { + Role string `json:"role"` + Content string `json:"content"` + ToolCalls []ToolCall `json:"tool_calls,omitempty"` +} + +type ToolCall struct { + ID string `json:"id"` + Type string `json:"type"` + FunctionName string `json:"function"` + FunctionArguments string `json:"arguments"` +} diff --git a/ui/chat.go b/ui/chat.go index cafd3c5..17801d3 100644 --- a/ui/chat.go +++ b/ui/chat.go @@ -12,13 +12,14 @@ import ( "charm.land/lipgloss/v2" "git.estatecloud.org/radumaco/souvenir/config" llm "git.estatecloud.org/radumaco/souvenir/llm" + "git.estatecloud.org/radumaco/souvenir/model" ) var logger *slog.Logger -type model struct { +type uiModel struct { viewport viewport.Model - messages []llm.Message + messages []model.Message textarea textarea.Model senderStyle lipgloss.Style agentStyle lipgloss.Style @@ -31,11 +32,11 @@ type model struct { } type agentResponseMessage struct { - response []llm.Message + response []model.Message err error } -func InitialModel(config config.Config) model { +func InitialModel(config config.Config) uiModel { logger = slog.Default().With("Component", "UI") ta := textarea.New() ta.Placeholder = "Send a message..." @@ -61,9 +62,9 @@ func InitialModel(config config.Config) model { ta.KeyMap.InsertNewline.SetEnabled(false) - return model{ + return uiModel{ textarea: ta, - messages: []llm.Message{}, + messages: []model.Message{}, viewport: vp, senderStyle: lipgloss.NewStyle().Foreground(lipgloss.Color("5")), errorStyle: lipgloss.NewStyle().Foreground(lipgloss.Color("9")), @@ -73,17 +74,17 @@ func InitialModel(config config.Config) model { } } -func (m model) Init() tea.Cmd { +func (m uiModel) Init() tea.Cmd { return textarea.Blink } -func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { +func (m uiModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.WindowSizeMsg: logger.Debug("Received WindowSizeMsg", "width", msg.Width, "height", msg.Height) m.viewport.SetWidth(msg.Width * 80 / 100) m.textarea.SetWidth(msg.Width * 80 / 100) - m.viewport.SetHeight(msg.Height - m.textarea.Height()) + m.viewport.SetHeight(msg.Height - lipgloss.Height(m.textarea.View())) m.width = msg.Width m.height = msg.Height @@ -94,18 +95,24 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } else { m.viewport.SetContent(renderLanding(m.viewport.Width(), m.viewport.Height())) } + logger.Debug("New sizes", + "vp width", m.viewport.Width(), "vp height", m.viewport.Height(), + "ta width", m.textarea.Width(), "ta height", m.textarea.Height()) m.viewport.GotoBottom() case tea.KeyPressMsg: - logger.Debug("Received KeyPressMsg") + logger.Debug("Received KeyPressMsg", "msg", msg) switch msg.String() { case "ctrl+c", "esc": logger.Debug("Received exit sequence. Quiting") fmt.Println(m.textarea.Value()) return m, tea.Quit + case "shift+enter", "ctrl+j", "alt+enter": + m.textarea.InsertRune('\n') + return m, nil case "enter": input := m.textarea.Value() - m.messages = append(m.messages, llm.Message{ + m.messages = append(m.messages, model.Message{ Content: input, Role: "user", }) @@ -134,7 +141,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { resp := msg.response if msg.err != nil { logger.Error("Message is error", "error", msg.err) - resp = []llm.Message{{ + resp = []model.Message{{ Role: "Error", Content: msg.err.Error(), }} @@ -146,13 +153,14 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } var messages = m.renderMessages() m.viewport.SetContent(lipgloss.NewStyle().Width(m.viewport.Width()).Render(messages)) + m.viewport.GotoBottom() return m, nil } return m, nil } -func (m model) View() tea.View { +func (m uiModel) View() tea.View { ui := lipgloss.JoinVertical( lipgloss.Left, m.viewport.View(), @@ -169,7 +177,7 @@ func (m model) View() tea.View { return view } -func (m model) callAgent(input string, messages []llm.Message) tea.Cmd { +func (m uiModel) callAgent(input string, messages []model.Message) tea.Cmd { logger.Debug("Calling agent", "query", input, "messages", messages) return func() tea.Msg { resp, err := m.client.Call(input, messages) @@ -177,7 +185,7 @@ func (m model) callAgent(input string, messages []llm.Message) tea.Cmd { } } -func (m model) renderMessages() string { +func (m uiModel) renderMessages() string { var result strings.Builder var width = m.viewport.Width() for _, message := range m.messages { diff --git a/ui/landing.go b/ui/landing.go index 6a54c88..1fb9ab3 100644 --- a/ui/landing.go +++ b/ui/landing.go @@ -2,17 +2,35 @@ package ui import "charm.land/lipgloss/v2" -// Logo is the souvenir snow-globe banner (ANSI 256-color, half-block). -const Logo = "\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m\x1b[38;5;111m▄\x1b[0m\x1b[38;5;111m▄\x1b[38;5;111;48;5;152m▀\x1b[38;5;111;48;5;152m▀\x1b[38;5;111;48;5;152m▀\x1b[38;5;111;48;5;152m▀\x1b[0m\x1b[38;5;111m▄\x1b[0m\x1b[38;5;111m▄\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m\n" + - "\x1b[0m \x1b[0m \x1b[0m\x1b[38;5;111m▄\x1b[38;5;111;48;5;111m▀\x1b[38;5;111;48;5;152m▀\x1b[38;5;152;48;5;195m▀\x1b[38;5;152;48;5;231m▀\x1b[38;5;152;48;5;195m▀\x1b[38;5;195;48;5;195m▀\x1b[38;5;195;48;5;152m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;111;48;5;152m▀\x1b[38;5;111;48;5;111m▀\x1b[0m\x1b[38;5;111m▄\x1b[0m \x1b[0m \x1b[0m\n" + - "\x1b[0m \x1b[0m\x1b[38;5;111m▄\x1b[38;5;111;48;5;152m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;195;48;5;195m▀\x1b[38;5;195;48;5;231m▀\x1b[38;5;195;48;5;195m▀\x1b[38;5;195;48;5;152m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;231;48;5;152m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;111;48;5;152m▀\x1b[0m\x1b[38;5;111m▄\x1b[0m \x1b[0m\n" + - "\x1b[0m \x1b[38;5;111;48;5;111m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;195;48;5;195m▀\x1b[38;5;195;48;5;195m▀\x1b[38;5;195;48;5;152m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;152;48;5;28m▀\x1b[38;5;152;48;5;22m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;231;48;5;152m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;111;48;5;111m▀\x1b[0m \x1b[0m\n" + - "\x1b[0m \x1b[38;5;152;48;5;152m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;195;48;5;152m▀\x1b[38;5;152;48;5;231m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;28;48;5;28m▀\x1b[38;5;28;48;5;28m▀\x1b[38;5;28;48;5;28m▀\x1b[38;5;22;48;5;22m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;231;48;5;152m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;152;48;5;152m▀\x1b[0m \x1b[0m\n" + - "\x1b[0m \x1b[38;5;111;48;5;111m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;28;48;5;28m▀\x1b[38;5;28;48;5;28m▀\x1b[38;5;28;48;5;28m▀\x1b[38;5;28;48;5;28m▀\x1b[38;5;28;48;5;28m▀\x1b[38;5;22;48;5;22m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;152;48;5;152m▀\x1b[38;5;111;48;5;111m▀\x1b[0m \x1b[0m\n" + - "\x1b[0m \x1b[0m\x1b[38;5;111m▀\x1b[38;5;231;48;5;111m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;94;48;5;231m▀\x1b[38;5;94;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;111m▀\x1b[0m\x1b[38;5;111m▀\x1b[0m \x1b[0m\n" + - "\x1b[0m \x1b[0m \x1b[0m \x1b[0m\x1b[38;5;130m▄\x1b[38;5;214;48;5;130m▀\x1b[38;5;214;48;5;130m▀\x1b[38;5;214;48;5;130m▀\x1b[38;5;214;48;5;130m▀\x1b[38;5;214;48;5;130m▀\x1b[38;5;214;48;5;130m▀\x1b[38;5;214;48;5;130m▀\x1b[38;5;214;48;5;130m▀\x1b[38;5;214;48;5;130m▀\x1b[38;5;214;48;5;130m▀\x1b[0m\x1b[38;5;130m▄\x1b[0m \x1b[0m \x1b[0m \x1b[0m\n" + - "\x1b[0m \x1b[0m \x1b[0m \x1b[0m\x1b[38;5;130m▀\x1b[38;5;130;48;5;94m▀\x1b[38;5;130;48;5;94m▀\x1b[38;5;130;48;5;94m▀\x1b[38;5;130;48;5;94m▀\x1b[38;5;130;48;5;94m▀\x1b[38;5;130;48;5;94m▀\x1b[38;5;130;48;5;94m▀\x1b[38;5;130;48;5;94m▀\x1b[38;5;130;48;5;94m▀\x1b[38;5;130;48;5;94m▀\x1b[0m\x1b[38;5;130m▀\x1b[0m \x1b[0m \x1b[0m \x1b[0m\n" + - "\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m\n" +// Logo is the synthwave sunset postcard (tilted, ANSI 256-color, half-block). +const Logo = "\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m\n" + + "\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m\x1b[38;5;231m▄\x1b[0m\x1b[38;5;231m▄\x1b[0m\x1b[38;5;231m▄\x1b[0m\x1b[38;5;231m▄\x1b[0m\x1b[38;5;231m▄\x1b[0m\x1b[38;5;231m▄\x1b[0m\x1b[38;5;231m▄\x1b[0m\x1b[38;5;231m▄\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m\n" + + "\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m\x1b[38;5;231m▄\x1b[0m\x1b[38;5;231m▄\x1b[0m\x1b[38;5;231m▄\x1b[0m\x1b[38;5;231m▄\x1b[0m\x1b[38;5;231m▄\x1b[0m\x1b[38;5;231m▄\x1b[0m\x1b[38;5;231m▄\x1b[0m\x1b[38;5;231m▄\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m\n" + + "\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m\x1b[38;5;231m▄\x1b[0m\x1b[38;5;231m▄\x1b[0m\x1b[38;5;231m▄\x1b[0m\x1b[38;5;231m▄\x1b[0m\x1b[38;5;231m▄\x1b[0m\x1b[38;5;231m▄\x1b[0m\x1b[38;5;231m▄\x1b[0m\x1b[38;5;231m▄\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m\n" + + "\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m\x1b[38;5;231m▄\x1b[0m\x1b[38;5;231m▄\x1b[0m\x1b[38;5;231m▄\x1b[0m\x1b[38;5;231m▄\x1b[0m\x1b[38;5;231m▄\x1b[0m\x1b[38;5;231m▄\x1b[0m\x1b[38;5;231m▄\x1b[0m\x1b[38;5;231m▄\x1b[0m\x1b[38;5;231m▄\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;90m▀\x1b[38;5;231;48;5;90m▀\x1b[38;5;231;48;5;90m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;90m▀\x1b[38;5;231;48;5;90m▀\x1b[38;5;231;48;5;90m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m\n" + + "\x1b[0m \x1b[0m \x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;90m▀\x1b[38;5;231;48;5;90m▀\x1b[38;5;231;48;5;252m▀\x1b[38;5;231;48;5;252m▀\x1b[38;5;231;48;5;252m▀\x1b[38;5;231;48;5;252m▀\x1b[38;5;231;48;5;252m▀\x1b[38;5;231;48;5;125m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;90;48;5;90m▀\x1b[38;5;90;48;5;16m▀\x1b[38;5;90;48;5;90m▀\x1b[38;5;90;48;5;125m▀\x1b[38;5;90;48;5;90m▀\x1b[38;5;125;48;5;90m▀\x1b[38;5;90;48;5;125m▀\x1b[38;5;125;48;5;90m▀\x1b[38;5;90;48;5;125m▀\x1b[38;5;231;48;5;90m▀\x1b[38;5;90;48;5;125m▀\x1b[38;5;125;48;5;90m▀\x1b[38;5;90;48;5;125m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m\n" + + "\x1b[0m \x1b[0m \x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;90m▀\x1b[38;5;231;48;5;90m▀\x1b[38;5;231;48;5;90m▀\x1b[38;5;231;48;5;90m▀\x1b[38;5;231;48;5;90m▀\x1b[38;5;231;48;5;90m▀\x1b[38;5;231;48;5;90m▀\x1b[38;5;231;48;5;90m▀\x1b[38;5;231;48;5;90m▀\x1b[38;5;90;48;5;125m▀\x1b[38;5;90;48;5;90m▀\x1b[38;5;90;48;5;125m▀\x1b[38;5;90;48;5;90m▀\x1b[38;5;90;48;5;125m▀\x1b[38;5;90;48;5;90m▀\x1b[38;5;90;48;5;125m▀\x1b[38;5;231;48;5;125m▀\x1b[38;5;125;48;5;252m▀\x1b[38;5;252;48;5;252m▀\x1b[38;5;252;48;5;16m▀\x1b[38;5;90;48;5;125m▀\x1b[38;5;125;48;5;90m▀\x1b[38;5;90;48;5;125m▀\x1b[38;5;252;48;5;90m▀\x1b[38;5;252;48;5;125m▀\x1b[38;5;252;48;5;252m▀\x1b[38;5;231;48;5;125m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;16;48;5;125m▀\x1b[38;5;90;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;90;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m\n" + + "\x1b[0m \x1b[0m \x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;90m▀\x1b[38;5;231;48;5;90m▀\x1b[38;5;231;48;5;90m▀\x1b[38;5;231;48;5;90m▀\x1b[38;5;231;48;5;90m▀\x1b[38;5;231;48;5;90m▀\x1b[38;5;231;48;5;90m▀\x1b[38;5;231;48;5;90m▀\x1b[38;5;90;48;5;90m▀\x1b[38;5;90;48;5;125m▀\x1b[38;5;90;48;5;90m▀\x1b[38;5;90;48;5;125m▀\x1b[38;5;90;48;5;90m▀\x1b[38;5;90;48;5;125m▀\x1b[38;5;90;48;5;90m▀\x1b[38;5;90;48;5;125m▀\x1b[38;5;90;48;5;125m▀\x1b[38;5;125;48;5;90m▀\x1b[38;5;90;48;5;125m▀\x1b[38;5;125;48;5;90m▀\x1b[38;5;90;48;5;125m▀\x1b[38;5;125;48;5;90m▀\x1b[38;5;90;48;5;125m▀\x1b[38;5;125;48;5;90m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;90;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;90;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;90;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;125;48;5;231m▀\x1b[38;5;252;48;5;125m▀\x1b[38;5;16;48;5;252m▀\x1b[38;5;231;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;231;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;231;48;5;16m▀\x1b[38;5;16;48;5;125m▀\x1b[38;5;252;48;5;161m▀\x1b[38;5;125;48;5;252m▀\x1b[38;5;231;48;5;161m▀\x1b[38;5;125;48;5;231m▀\x1b[38;5;125;48;5;161m▀\x1b[38;5;125;48;5;161m▀\x1b[38;5;125;48;5;161m▀\x1b[38;5;125;48;5;161m▀\x1b[38;5;161;48;5;161m▀\x1b[38;5;161;48;5;161m▀\x1b[38;5;161;48;5;161m▀\x1b[38;5;161;48;5;161m▀\x1b[38;5;161;48;5;161m▀\x1b[38;5;161;48;5;161m▀\x1b[38;5;161;48;5;161m▀\x1b[38;5;161;48;5;161m▀\x1b[38;5;231;48;5;197m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m\n" + + "\x1b[0m \x1b[0m \x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;90;48;5;90m▀\x1b[38;5;90;48;5;90m▀\x1b[38;5;90;48;5;90m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;90;48;5;90m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;90;48;5;90m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;90;48;5;90m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;90;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;90;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;90;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;90;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;125;48;5;161m▀\x1b[38;5;125;48;5;161m▀\x1b[38;5;125;48;5;161m▀\x1b[38;5;125;48;5;161m▀\x1b[38;5;125;48;5;161m▀\x1b[38;5;125;48;5;161m▀\x1b[38;5;125;48;5;161m▀\x1b[38;5;125;48;5;161m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;161;48;5;161m▀\x1b[38;5;252;48;5;252m▀\x1b[38;5;161;48;5;252m▀\x1b[38;5;231;48;5;161m▀\x1b[38;5;161;48;5;161m▀\x1b[38;5;231;48;5;161m▀\x1b[38;5;161;48;5;161m▀\x1b[38;5;231;48;5;161m▀\x1b[38;5;252;48;5;252m▀\x1b[38;5;252;48;5;197m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;161;48;5;197m▀\x1b[38;5;161;48;5;197m▀\x1b[38;5;161;48;5;197m▀\x1b[38;5;161;48;5;197m▀\x1b[38;5;197;48;5;202m▀\x1b[38;5;197;48;5;197m▀\x1b[38;5;197;48;5;202m▀\x1b[38;5;197;48;5;197m▀\x1b[38;5;197;48;5;202m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;197;48;5;202m▀\x1b[38;5;197;48;5;197m▀\x1b[38;5;202;48;5;202m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m\n" + + "\x1b[0m \x1b[0m \x1b[0m \x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;125;48;5;125m▀\x1b[38;5;125;48;5;161m▀\x1b[38;5;125;48;5;161m▀\x1b[38;5;125;48;5;161m▀\x1b[38;5;125;48;5;161m▀\x1b[38;5;125;48;5;161m▀\x1b[38;5;125;48;5;161m▀\x1b[38;5;125;48;5;161m▀\x1b[38;5;125;48;5;161m▀\x1b[38;5;161;48;5;161m▀\x1b[38;5;161;48;5;161m▀\x1b[38;5;161;48;5;161m▀\x1b[38;5;161;48;5;161m▀\x1b[38;5;161;48;5;161m▀\x1b[38;5;161;48;5;161m▀\x1b[38;5;161;48;5;161m▀\x1b[38;5;161;48;5;161m▀\x1b[38;5;161;48;5;197m▀\x1b[38;5;161;48;5;231m▀\x1b[38;5;161;48;5;231m▀\x1b[38;5;161;48;5;231m▀\x1b[38;5;16;48;5;231m▀\x1b[38;5;161;48;5;16m▀\x1b[38;5;16;48;5;231m▀\x1b[38;5;161;48;5;231m▀\x1b[38;5;231;48;5;197m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;197;48;5;231m▀\x1b[38;5;252;48;5;202m▀\x1b[38;5;252;48;5;197m▀\x1b[38;5;197;48;5;252m▀\x1b[38;5;197;48;5;252m▀\x1b[38;5;197;48;5;252m▀\x1b[38;5;252;48;5;252m▀\x1b[38;5;202;48;5;231m▀\x1b[38;5;231;48;5;208m▀\x1b[38;5;231;48;5;202m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;202;48;5;231m▀\x1b[38;5;197;48;5;231m▀\x1b[38;5;202;48;5;202m▀\x1b[38;5;197;48;5;208m▀\x1b[38;5;202;48;5;208m▀\x1b[38;5;208;48;5;202m▀\x1b[38;5;202;48;5;208m▀\x1b[38;5;231;48;5;202m▀\x1b[38;5;231;48;5;208m▀\x1b[38;5;231;48;5;202m▀\x1b[38;5;202;48;5;208m▀\x1b[38;5;208;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m\n" + + "\x1b[0m \x1b[0m \x1b[0m \x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;125;48;5;161m▀\x1b[38;5;161;48;5;161m▀\x1b[38;5;161;48;5;161m▀\x1b[38;5;161;48;5;161m▀\x1b[38;5;161;48;5;161m▀\x1b[38;5;161;48;5;161m▀\x1b[38;5;161;48;5;161m▀\x1b[38;5;161;48;5;161m▀\x1b[38;5;161;48;5;161m▀\x1b[38;5;161;48;5;197m▀\x1b[38;5;161;48;5;197m▀\x1b[38;5;161;48;5;197m▀\x1b[38;5;161;48;5;197m▀\x1b[38;5;161;48;5;197m▀\x1b[38;5;161;48;5;197m▀\x1b[38;5;161;48;5;197m▀\x1b[38;5;161;48;5;197m▀\x1b[38;5;197;48;5;197m▀\x1b[38;5;197;48;5;202m▀\x1b[38;5;197;48;5;197m▀\x1b[38;5;197;48;5;202m▀\x1b[38;5;197;48;5;197m▀\x1b[38;5;197;48;5;202m▀\x1b[38;5;197;48;5;197m▀\x1b[38;5;197;48;5;202m▀\x1b[38;5;231;48;5;229m▀\x1b[38;5;231;48;5;229m▀\x1b[38;5;231;48;5;229m▀\x1b[38;5;231;48;5;229m▀\x1b[38;5;231;48;5;229m▀\x1b[38;5;231;48;5;229m▀\x1b[38;5;231;48;5;229m▀\x1b[38;5;231;48;5;229m▀\x1b[38;5;231;48;5;229m▀\x1b[38;5;229;48;5;229m▀\x1b[38;5;231;48;5;229m▀\x1b[38;5;231;48;5;208m▀\x1b[38;5;208;48;5;231m▀\x1b[38;5;202;48;5;231m▀\x1b[38;5;208;48;5;231m▀\x1b[38;5;202;48;5;231m▀\x1b[38;5;208;48;5;231m▀\x1b[38;5;208;48;5;208m▀\x1b[38;5;202;48;5;214m▀\x1b[38;5;208;48;5;208m▀\x1b[38;5;202;48;5;214m▀\x1b[38;5;208;48;5;208m▀\x1b[38;5;202;48;5;214m▀\x1b[38;5;208;48;5;208m▀\x1b[38;5;202;48;5;214m▀\x1b[38;5;208;48;5;214m▀\x1b[38;5;214;48;5;214m▀\x1b[38;5;208;48;5;54m▀\x1b[38;5;214;48;5;54m▀\x1b[38;5;208;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m\n" + + "\x1b[0m \x1b[0m \x1b[0m \x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;161;48;5;197m▀\x1b[38;5;197;48;5;197m▀\x1b[38;5;197;48;5;202m▀\x1b[38;5;197;48;5;197m▀\x1b[38;5;197;48;5;202m▀\x1b[38;5;197;48;5;197m▀\x1b[38;5;197;48;5;202m▀\x1b[38;5;197;48;5;197m▀\x1b[38;5;197;48;5;202m▀\x1b[38;5;197;48;5;208m▀\x1b[38;5;202;48;5;202m▀\x1b[38;5;197;48;5;208m▀\x1b[38;5;202;48;5;202m▀\x1b[38;5;197;48;5;208m▀\x1b[38;5;202;48;5;202m▀\x1b[38;5;197;48;5;208m▀\x1b[38;5;202;48;5;202m▀\x1b[38;5;208;48;5;202m▀\x1b[38;5;202;48;5;208m▀\x1b[38;5;208;48;5;202m▀\x1b[38;5;202;48;5;208m▀\x1b[38;5;208;48;5;202m▀\x1b[38;5;202;48;5;208m▀\x1b[38;5;208;48;5;229m▀\x1b[38;5;229;48;5;229m▀\x1b[38;5;229;48;5;229m▀\x1b[38;5;229;48;5;229m▀\x1b[38;5;229;48;5;229m▀\x1b[38;5;229;48;5;229m▀\x1b[38;5;229;48;5;229m▀\x1b[38;5;229;48;5;229m▀\x1b[38;5;229;48;5;229m▀\x1b[38;5;229;48;5;229m▀\x1b[38;5;229;48;5;229m▀\x1b[38;5;229;48;5;227m▀\x1b[38;5;229;48;5;227m▀\x1b[38;5;208;48;5;227m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;208;48;5;54m▀\x1b[38;5;214;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;214;48;5;54m▀\x1b[38;5;214;48;5;54m▀\x1b[38;5;214;48;5;54m▀\x1b[38;5;214;48;5;54m▀\x1b[38;5;214;48;5;54m▀\x1b[38;5;214;48;5;214m▀\x1b[38;5;214;48;5;214m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;231;48;5;54m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[0m \x1b[0m \x1b[0m \x1b[0m\n" + + "\x1b[0m \x1b[0m \x1b[0m \x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;202;48;5;202m▀\x1b[38;5;208;48;5;202m▀\x1b[38;5;202;48;5;208m▀\x1b[38;5;208;48;5;16m▀\x1b[38;5;202;48;5;16m▀\x1b[38;5;208;48;5;208m▀\x1b[38;5;202;48;5;202m▀\x1b[38;5;208;48;5;208m▀\x1b[38;5;202;48;5;202m▀\x1b[38;5;202;48;5;208m▀\x1b[38;5;208;48;5;214m▀\x1b[38;5;202;48;5;208m▀\x1b[38;5;208;48;5;16m▀\x1b[38;5;202;48;5;208m▀\x1b[38;5;208;48;5;214m▀\x1b[38;5;202;48;5;208m▀\x1b[38;5;208;48;5;214m▀\x1b[38;5;214;48;5;208m▀\x1b[38;5;208;48;5;214m▀\x1b[38;5;214;48;5;214m▀\x1b[38;5;214;48;5;214m▀\x1b[38;5;208;48;5;214m▀\x1b[38;5;214;48;5;214m▀\x1b[38;5;208;48;5;54m▀\x1b[38;5;229;48;5;54m▀\x1b[38;5;229;48;5;54m▀\x1b[38;5;227;48;5;54m▀\x1b[38;5;227;48;5;54m▀\x1b[38;5;227;48;5;54m▀\x1b[38;5;227;48;5;227m▀\x1b[38;5;227;48;5;227m▀\x1b[38;5;227;48;5;227m▀\x1b[38;5;227;48;5;227m▀\x1b[38;5;227;48;5;227m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[0m \x1b[0m \x1b[0m \x1b[0m\n" + + "\x1b[0m \x1b[0m \x1b[0m \x1b[0m\x1b[38;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;208;48;5;16m▀\x1b[38;5;214;48;5;16m▀\x1b[38;5;208;48;5;54m▀\x1b[38;5;16;48;5;16m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;16m▀\x1b[38;5;208;48;5;16m▀\x1b[38;5;214;48;5;54m▀\x1b[38;5;54;48;5;16m▀\x1b[38;5;214;48;5;16m▀\x1b[38;5;214;48;5;54m▀\x1b[38;5;16;48;5;16m▀\x1b[38;5;214;48;5;54m▀\x1b[38;5;214;48;5;16m▀\x1b[38;5;214;48;5;16m▀\x1b[38;5;214;48;5;214m▀\x1b[38;5;214;48;5;214m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;214;48;5;54m▀\x1b[38;5;214;48;5;54m▀\x1b[38;5;214;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;51m▀\x1b[38;5;54;48;5;30m▀\x1b[38;5;54;48;5;30m▀\x1b[38;5;54;48;5;51m▀\x1b[38;5;54;48;5;30m▀\x1b[38;5;54;48;5;30m▀\x1b[38;5;54;48;5;51m▀\x1b[38;5;54;48;5;30m▀\x1b[38;5;54;48;5;30m▀\x1b[38;5;51;48;5;31m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[0m \x1b[0m \x1b[0m \x1b[0m\n" + + "\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;54;48;5;16m▀\x1b[38;5;54;48;5;16m▀\x1b[38;5;16;48;5;16m▀\x1b[38;5;16;48;5;16m▀\x1b[38;5;16;48;5;16m▀\x1b[38;5;54;48;5;16m▀\x1b[38;5;54;48;5;16m▀\x1b[38;5;54;48;5;16m▀\x1b[38;5;16;48;5;16m▀\x1b[38;5;54;48;5;16m▀\x1b[38;5;16;48;5;16m▀\x1b[38;5;16;48;5;16m▀\x1b[38;5;16;48;5;16m▀\x1b[38;5;54;48;5;16m▀\x1b[38;5;54;48;5;16m▀\x1b[38;5;54;48;5;16m▀\x1b[38;5;54;48;5;16m▀\x1b[38;5;54;48;5;16m▀\x1b[38;5;54;48;5;16m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;30m▀\x1b[38;5;54;48;5;51m▀\x1b[38;5;54;48;5;30m▀\x1b[38;5;54;48;5;30m▀\x1b[38;5;54;48;5;51m▀\x1b[38;5;54;48;5;30m▀\x1b[38;5;54;48;5;30m▀\x1b[38;5;54;48;5;51m▀\x1b[38;5;30;48;5;31m▀\x1b[38;5;30;48;5;31m▀\x1b[38;5;51;48;5;31m▀\x1b[38;5;30;48;5;31m▀\x1b[38;5;30;48;5;31m▀\x1b[38;5;51;48;5;31m▀\x1b[38;5;30;48;5;31m▀\x1b[38;5;30;48;5;31m▀\x1b[38;5;51;48;5;31m▀\x1b[38;5;31;48;5;51m▀\x1b[38;5;31;48;5;31m▀\x1b[38;5;31;48;5;37m▀\x1b[38;5;37;48;5;51m▀\x1b[38;5;31;48;5;37m▀\x1b[38;5;37;48;5;37m▀\x1b[38;5;31;48;5;51m▀\x1b[38;5;37;48;5;37m▀\x1b[38;5;37;48;5;38m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[0m \x1b[0m \x1b[0m \x1b[0m\n" + + "\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;16;48;5;54m▀\x1b[38;5;16;48;5;54m▀\x1b[38;5;16;48;5;54m▀\x1b[38;5;16;48;5;16m▀\x1b[38;5;16;48;5;16m▀\x1b[38;5;16;48;5;54m▀\x1b[38;5;16;48;5;54m▀\x1b[38;5;16;48;5;16m▀\x1b[38;5;16;48;5;16m▀\x1b[38;5;16;48;5;54m▀\x1b[38;5;16;48;5;54m▀\x1b[38;5;16;48;5;16m▀\x1b[38;5;16;48;5;54m▀\x1b[38;5;16;48;5;54m▀\x1b[38;5;54;48;5;16m▀\x1b[38;5;54;48;5;16m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;30m▀\x1b[38;5;54;48;5;30m▀\x1b[38;5;16;48;5;51m▀\x1b[38;5;54;48;5;30m▀\x1b[38;5;54;48;5;30m▀\x1b[38;5;54;48;5;51m▀\x1b[38;5;54;48;5;30m▀\x1b[38;5;54;48;5;30m▀\x1b[38;5;51;48;5;31m▀\x1b[38;5;30;48;5;31m▀\x1b[38;5;30;48;5;231m▀\x1b[38;5;231;48;5;31m▀\x1b[38;5;30;48;5;231m▀\x1b[38;5;231;48;5;31m▀\x1b[38;5;51;48;5;231m▀\x1b[38;5;30;48;5;31m▀\x1b[38;5;31;48;5;31m▀\x1b[38;5;31;48;5;31m▀\x1b[38;5;31;48;5;51m▀\x1b[38;5;31;48;5;31m▀\x1b[38;5;31;48;5;31m▀\x1b[38;5;31;48;5;51m▀\x1b[38;5;31;48;5;51m▀\x1b[38;5;31;48;5;31m▀\x1b[38;5;51;48;5;31m▀\x1b[38;5;31;48;5;37m▀\x1b[38;5;31;48;5;37m▀\x1b[38;5;51;48;5;37m▀\x1b[38;5;31;48;5;37m▀\x1b[38;5;31;48;5;37m▀\x1b[38;5;51;48;5;37m▀\x1b[38;5;37;48;5;38m▀\x1b[38;5;31;48;5;37m▀\x1b[38;5;37;48;5;38m▀\x1b[38;5;38;48;5;38m▀\x1b[38;5;38;48;5;51m▀\x1b[38;5;45;48;5;195m▀\x1b[38;5;38;48;5;230m▀\x1b[38;5;38;48;5;195m▀\x1b[38;5;45;48;5;230m▀\x1b[38;5;38;48;5;195m▀\x1b[38;5;230;48;5;230m▀\x1b[38;5;231;48;5;222m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[0m \x1b[0m \x1b[0m\n" + + "\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;54;48;5;54m▀\x1b[38;5;54;48;5;51m▀\x1b[38;5;54;48;5;30m▀\x1b[38;5;54;48;5;30m▀\x1b[38;5;16;48;5;16m▀\x1b[38;5;54;48;5;30m▀\x1b[38;5;54;48;5;30m▀\x1b[38;5;16;48;5;30m▀\x1b[38;5;16;48;5;16m▀\x1b[38;5;16;48;5;30m▀\x1b[38;5;51;48;5;16m▀\x1b[38;5;30;48;5;30m▀\x1b[38;5;16;48;5;31m▀\x1b[38;5;51;48;5;16m▀\x1b[38;5;30;48;5;31m▀\x1b[38;5;16;48;5;31m▀\x1b[38;5;51;48;5;31m▀\x1b[38;5;16;48;5;31m▀\x1b[38;5;31;48;5;16m▀\x1b[38;5;31;48;5;37m▀\x1b[38;5;31;48;5;31m▀\x1b[38;5;31;48;5;51m▀\x1b[38;5;31;48;5;31m▀\x1b[38;5;31;48;5;37m▀\x1b[38;5;31;48;5;51m▀\x1b[38;5;37;48;5;37m▀\x1b[38;5;31;48;5;38m▀\x1b[38;5;51;48;5;37m▀\x1b[38;5;31;48;5;38m▀\x1b[38;5;226;48;5;37m▀\x1b[38;5;51;48;5;226m▀\x1b[38;5;226;48;5;37m▀\x1b[38;5;31;48;5;37m▀\x1b[38;5;37;48;5;38m▀\x1b[38;5;37;48;5;51m▀\x1b[38;5;37;48;5;37m▀\x1b[38;5;37;48;5;37m▀\x1b[38;5;37;48;5;51m▀\x1b[38;5;37;48;5;37m▀\x1b[38;5;37;48;5;37m▀\x1b[38;5;37;48;5;51m▀\x1b[38;5;37;48;5;37m▀\x1b[38;5;37;48;5;38m▀\x1b[38;5;51;48;5;38m▀\x1b[38;5;37;48;5;38m▀\x1b[38;5;38;48;5;38m▀\x1b[38;5;51;48;5;38m▀\x1b[38;5;38;48;5;38m▀\x1b[38;5;37;48;5;45m▀\x1b[38;5;51;48;5;38m▀\x1b[38;5;230;48;5;222m▀\x1b[38;5;195;48;5;230m▀\x1b[38;5;230;48;5;222m▀\x1b[38;5;222;48;5;230m▀\x1b[38;5;230;48;5;222m▀\x1b[38;5;222;48;5;230m▀\x1b[38;5;230;48;5;222m▀\x1b[38;5;222;48;5;230m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;230;48;5;222m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[0m \x1b[0m \x1b[0m\n" + + "\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m\x1b[38;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;30;48;5;31m▀\x1b[38;5;31;48;5;31m▀\x1b[38;5;30;48;5;51m▀\x1b[38;5;31;48;5;30m▀\x1b[38;5;30;48;5;31m▀\x1b[38;5;16;48;5;16m▀\x1b[38;5;16;48;5;31m▀\x1b[38;5;31;48;5;31m▀\x1b[38;5;51;48;5;31m▀\x1b[38;5;31;48;5;37m▀\x1b[38;5;31;48;5;31m▀\x1b[38;5;51;48;5;37m▀\x1b[38;5;31;48;5;31m▀\x1b[38;5;16;48;5;16m▀\x1b[38;5;51;48;5;37m▀\x1b[38;5;31;48;5;37m▀\x1b[38;5;37;48;5;38m▀\x1b[38;5;37;48;5;37m▀\x1b[38;5;37;48;5;51m▀\x1b[38;5;38;48;5;37m▀\x1b[38;5;37;48;5;38m▀\x1b[38;5;38;48;5;51m▀\x1b[38;5;37;48;5;38m▀\x1b[38;5;38;48;5;38m▀\x1b[38;5;51;48;5;195m▀\x1b[38;5;38;48;5;230m▀\x1b[38;5;38;48;5;195m▀\x1b[38;5;51;48;5;230m▀\x1b[38;5;38;48;5;38m▀\x1b[38;5;37;48;5;226m▀\x1b[38;5;51;48;5;38m▀\x1b[38;5;37;48;5;38m▀\x1b[38;5;38;48;5;38m▀\x1b[38;5;38;48;5;38m▀\x1b[38;5;38;48;5;51m▀\x1b[38;5;38;48;5;38m▀\x1b[38;5;38;48;5;38m▀\x1b[38;5;38;48;5;51m▀\x1b[38;5;38;48;5;38m▀\x1b[38;5;38;48;5;38m▀\x1b[38;5;38;48;5;51m▀\x1b[38;5;38;48;5;45m▀\x1b[38;5;38;48;5;45m▀\x1b[38;5;51;48;5;45m▀\x1b[38;5;45;48;5;195m▀\x1b[38;5;38;48;5;230m▀\x1b[38;5;51;48;5;195m▀\x1b[38;5;230;48;5;230m▀\x1b[38;5;195;48;5;222m▀\x1b[38;5;230;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;230;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[0m \x1b[0m \x1b[0m\n" + + "\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;31;48;5;51m▀\x1b[38;5;37;48;5;31m▀\x1b[38;5;31;48;5;37m▀\x1b[38;5;37;48;5;51m▀\x1b[38;5;31;48;5;37m▀\x1b[38;5;16;48;5;31m▀\x1b[38;5;31;48;5;16m▀\x1b[38;5;37;48;5;31m▀\x1b[38;5;37;48;5;37m▀\x1b[38;5;51;48;5;38m▀\x1b[38;5;37;48;5;37m▀\x1b[38;5;37;48;5;38m▀\x1b[38;5;51;48;5;37m▀\x1b[38;5;16;48;5;16m▀\x1b[38;5;37;48;5;38m▀\x1b[38;5;51;48;5;38m▀\x1b[38;5;38;48;5;51m▀\x1b[38;5;38;48;5;38m▀\x1b[38;5;38;48;5;195m▀\x1b[38;5;45;48;5;230m▀\x1b[38;5;195;48;5;230m▀\x1b[38;5;230;48;5;222m▀\x1b[38;5;195;48;5;230m▀\x1b[38;5;230;48;5;222m▀\x1b[38;5;230;48;5;222m▀\x1b[38;5;222;48;5;230m▀\x1b[38;5;230;48;5;222m▀\x1b[38;5;222;48;5;230m▀\x1b[38;5;195;48;5;222m▀\x1b[38;5;230;48;5;230m▀\x1b[38;5;195;48;5;222m▀\x1b[38;5;51;48;5;230m▀\x1b[38;5;45;48;5;195m▀\x1b[38;5;230;48;5;222m▀\x1b[38;5;45;48;5;195m▀\x1b[38;5;45;48;5;230m▀\x1b[38;5;45;48;5;195m▀\x1b[38;5;45;48;5;230m▀\x1b[38;5;45;48;5;195m▀\x1b[38;5;45;48;5;230m▀\x1b[38;5;45;48;5;195m▀\x1b[38;5;230;48;5;230m▀\x1b[38;5;195;48;5;222m▀\x1b[38;5;230;48;5;230m▀\x1b[38;5;230;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;230;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;230;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[0m \x1b[0m \x1b[0m\n" + + "\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;37;48;5;38m▀\x1b[38;5;38;48;5;51m▀\x1b[38;5;37;48;5;38m▀\x1b[38;5;37;48;5;37m▀\x1b[38;5;37;48;5;51m▀\x1b[38;5;37;48;5;37m▀\x1b[38;5;16;48;5;16m▀\x1b[38;5;38;48;5;51m▀\x1b[38;5;38;48;5;38m▀\x1b[38;5;37;48;5;38m▀\x1b[38;5;51;48;5;38m▀\x1b[38;5;37;48;5;45m▀\x1b[38;5;38;48;5;38m▀\x1b[38;5;16;48;5;16m▀\x1b[38;5;16;48;5;16m▀\x1b[38;5;38;48;5;230m▀\x1b[38;5;195;48;5;230m▀\x1b[38;5;230;48;5;222m▀\x1b[38;5;222;48;5;230m▀\x1b[38;5;230;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;230;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;230;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;230;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;230;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;230;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;230;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;230;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;230;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;231;48;5;179m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[0m\x1b[38;5;231m▄\x1b[0m \x1b[0m\n" + + "\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;38;48;5;38m▀\x1b[38;5;38;48;5;38m▀\x1b[38;5;38;48;5;51m▀\x1b[38;5;38;48;5;38m▀\x1b[38;5;38;48;5;38m▀\x1b[38;5;38;48;5;51m▀\x1b[38;5;16;48;5;16m▀\x1b[38;5;38;48;5;16m▀\x1b[38;5;51;48;5;45m▀\x1b[38;5;38;48;5;45m▀\x1b[38;5;38;48;5;45m▀\x1b[38;5;51;48;5;45m▀\x1b[38;5;45;48;5;230m▀\x1b[38;5;16;48;5;195m▀\x1b[38;5;16;48;5;16m▀\x1b[38;5;222;48;5;16m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;137m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;137m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;137m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;137m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;137;48;5;137m▀\x1b[38;5;179;48;5;231m▀\x1b[38;5;137;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[0m \x1b[0m\n" + + "\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m\x1b[38;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;45;48;5;195m▀\x1b[38;5;45;48;5;230m▀\x1b[38;5;45;48;5;195m▀\x1b[38;5;45;48;5;51m▀\x1b[38;5;38;48;5;45m▀\x1b[38;5;45;48;5;38m▀\x1b[38;5;16;48;5;16m▀\x1b[38;5;16;48;5;16m▀\x1b[38;5;195;48;5;222m▀\x1b[38;5;230;48;5;230m▀\x1b[38;5;195;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;230;48;5;222m▀\x1b[38;5;16;48;5;222m▀\x1b[38;5;16;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;231m▀\x1b[38;5;179;48;5;231m▀\x1b[38;5;179;48;5;231m▀\x1b[38;5;179;48;5;231m▀\x1b[38;5;179;48;5;231m▀\x1b[38;5;179;48;5;231m▀\x1b[38;5;179;48;5;231m▀\x1b[38;5;179;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[0m \x1b[0m\n" + + "\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;230;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;230;48;5;222m▀\x1b[38;5;195;48;5;230m▀\x1b[38;5;230;48;5;222m▀\x1b[38;5;16;48;5;16m▀\x1b[38;5;16;48;5;16m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;222m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;137m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;137m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;179;48;5;137m▀\x1b[38;5;179;48;5;179m▀\x1b[38;5;137;48;5;231m▀\x1b[38;5;179;48;5;231m▀\x1b[38;5;137;48;5;231m▀\x1b[38;5;179;48;5;231m▀\x1b[38;5;137;48;5;231m▀\x1b[38;5;179;48;5;231m▀\x1b[38;5;137;48;5;231m▀\x1b[38;5;179;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[0m \x1b[0m\n" + + "\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;222;48;5;179m▀\x1b[38;5;16;48;5;179m▀\x1b[38;5;16;48;5;231m▀\x1b[38;5;179;48;5;231m▀\x1b[38;5;179;48;5;231m▀\x1b[38;5;179;48;5;231m▀\x1b[38;5;179;48;5;231m▀\x1b[38;5;179;48;5;231m▀\x1b[38;5;179;48;5;231m▀\x1b[38;5;179;48;5;231m▀\x1b[38;5;179;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m \x1b[0m\n" + + "\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m\n" + + "\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m\x1b[38;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;231;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;17m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m\n" + + "\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;17;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[38;5;231;48;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m\n" + + "\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m\x1b[38;5;231m▀\x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m \x1b[0m\n" const Wordmark = ` ___ ___ _ ___ _____ _ __ (_)_ __