From d6050c086f317414faeee2d1fe1ae62b28524800 Mon Sep 17 00:00:00 2001 From: Taran Nathan Date: Thu, 24 Sep 2026 12:42:46 -0700 Subject: [PATCH 1/1] prototype #1 --- client/.gitignore | 8 + client/README.md | 24 + client/gleam.toml | 30 + client/manifest.toml | 65 + client/src/client.gleam | 435 ++ client/static/cat.png | Bin 0 -> 65460 bytes client/test/client_test.gleam | 13 + css_to_lustre/.gitignore | 4 + css_to_lustre/README.md | 24 + css_to_lustre/gleam.toml | 20 + css_to_lustre/manifest.toml | 18 + css_to_lustre/src/css_to_lustre.gleam | 41 + css_to_lustre/test/css_to_lustre_test.gleam | 13 + server/.env | 1 + server/.gitignore | 4 + server/README.md | 32 + server/data.json | 1 + server/db/init.sql | 33 + server/gleam.toml | 34 + server/justfile | 7 + server/manifest.toml | 85 + server/src/database.gleam | 23 + server/src/server.gleam | 312 + server/src/sql.gleam | 155 + server/src/sql/create_project.sql | 3 + server/src/sql/create_session.sql | 2 + server/src/sql/create_task.sql | 3 + server/src/sql/create_user.sql | 4 + server/src/sql/find_session.sql | 3 + server/src/sql/find_user.sql | 3 + server/src/sql/list_projects.sql | 3 + server/src/sql/list_tasks.sql | 6 + server/src/sql/update_task_status.sql | 3 + server/static/cat.png | Bin 0 -> 65460 bytes server/static/client.js | 7708 +++++++++++++++++++ server/test/server_test.gleam | 13 + shared/.gitignore | 4 + shared/README.md | 24 + shared/gleam.toml | 21 + shared/manifest.toml | 21 + shared/src/shared.gleam | 155 + shared/test/shared_test.gleam | 13 + 42 files changed, 9371 insertions(+) create mode 100644 client/.gitignore create mode 100644 client/README.md create mode 100644 client/gleam.toml create mode 100644 client/manifest.toml create mode 100644 client/src/client.gleam create mode 100644 client/static/cat.png create mode 100644 client/test/client_test.gleam create mode 100644 css_to_lustre/.gitignore create mode 100644 css_to_lustre/README.md create mode 100644 css_to_lustre/gleam.toml create mode 100644 css_to_lustre/manifest.toml create mode 100644 css_to_lustre/src/css_to_lustre.gleam create mode 100644 css_to_lustre/test/css_to_lustre_test.gleam create mode 100644 server/.env create mode 100644 server/.gitignore create mode 100644 server/README.md create mode 100644 server/data.json create mode 100644 server/db/init.sql create mode 100644 server/gleam.toml create mode 100644 server/justfile create mode 100644 server/manifest.toml create mode 100644 server/src/database.gleam create mode 100644 server/src/server.gleam create mode 100644 server/src/sql.gleam create mode 100644 server/src/sql/create_project.sql create mode 100644 server/src/sql/create_session.sql create mode 100644 server/src/sql/create_task.sql create mode 100644 server/src/sql/create_user.sql create mode 100644 server/src/sql/find_session.sql create mode 100644 server/src/sql/find_user.sql create mode 100644 server/src/sql/list_projects.sql create mode 100644 server/src/sql/list_tasks.sql create mode 100644 server/src/sql/update_task_status.sql create mode 100644 server/static/cat.png create mode 100644 server/static/client.js create mode 100644 server/test/server_test.gleam create mode 100644 shared/.gitignore create mode 100644 shared/README.md create mode 100644 shared/gleam.toml create mode 100644 shared/manifest.toml create mode 100644 shared/src/shared.gleam create mode 100644 shared/test/shared_test.gleam diff --git a/client/.gitignore b/client/.gitignore new file mode 100644 index 0000000..ca614a3 --- /dev/null +++ b/client/.gitignore @@ -0,0 +1,8 @@ +*.beam +*.ez +/build +erl_crash.dump + +#Added automatically by Lustre Dev Tools +/.lustre +/dist diff --git a/client/README.md b/client/README.md new file mode 100644 index 0000000..a871ddc --- /dev/null +++ b/client/README.md @@ -0,0 +1,24 @@ +# client + +[![Package Version](https://img.shields.io/hexpm/v/client)](https://hex.pm/packages/client) +[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://client.hexdocs.pm/) + +```sh +gleam add client@1 +``` +```gleam +import client + +pub fn main() -> Nil { + // TODO: An example of the project in use +} +``` + +Further documentation can be found at . + +## Development + +```sh +gleam run # Run the project +gleam test # Run the tests +``` diff --git a/client/gleam.toml b/client/gleam.toml new file mode 100644 index 0000000..5f562d7 --- /dev/null +++ b/client/gleam.toml @@ -0,0 +1,30 @@ +name = "client" +version = "1.0.0" +target = "javascript" + +# Fill out these fields if you intend to generate HTML documentation or publish +# your project to the Hex package manager. +# +# description = "" +# licences = ["Apache-2.0"] +# repository = { type = "github", user = "", repo = "" } +# links = [{ title = "Website", href = "" }] +# +# For a full reference of all the available options, you can have a look at +# https://gleam.run/writing-gleam/gleam-toml/. + +[dependencies] +gleam_stdlib = ">= 1.0.0 and < 2.0.0" +lustre = ">= 5.7.1 and < 6.0.0" +rsvp = ">= 2.0.0 and < 3.0.0" +gleam_json = ">= 3.1.0 and < 4.0.0" +gleam_http = ">= 4.3.0 and < 5.0.0" +plinth = ">= 0.11.0 and < 1.0.0" +shared = { path = "../shared" } +gleam_erlang = ">= 1.3.0 and < 2.0.0" +mist = ">= 6.0.3 and < 7.0.0" +simplifile = ">= 2.7.0 and < 3.0.0" + +[dev_dependencies] +gleeunit = ">= 1.0.0 and < 2.0.0" +lustre_dev_tools = ">= 2.3.6 and < 3.0.0" diff --git a/client/manifest.toml b/client/manifest.toml new file mode 100644 index 0000000..b9b14b0 --- /dev/null +++ b/client/manifest.toml @@ -0,0 +1,65 @@ +# Do not manually edit this file, it is managed by Gleam. +# +# This file locks the dependency versions used, to make your build +# deterministic and to prevent unexpected versions from being included +# in your application. +# +# You should check this file into your source control repository. + +packages = [ + { name = "argv", version = "1.1.0", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "3277D100448BDB4A29B6D58C0F36F631CBC349E8BDD09766C6309DF202831140" }, + { name = "booklet", version = "1.1.0", build_tools = ["gleam"], requirements = [], otp_app = "booklet", source = "hex", outer_checksum = "08E0FDB78DC4D8A5D3C80295B021505C7D2A2E7B6C6D5EAB7286C36F4A53C851" }, + { name = "directories", version = "1.2.0", build_tools = ["gleam"], requirements = ["envoy", "gleam_stdlib", "platform", "simplifile"], otp_app = "directories", source = "hex", outer_checksum = "D13090CFCDF6759B87217E8DDD73A75903A700148A82C1D33799F333E249BF9E" }, + { name = "envoy", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "envoy", source = "hex", outer_checksum = "9C6FBB6BFA02A52798BEEC5977A738CAD6E4A057F4B67FD0C8061AD2502C191A" }, + { name = "exception", version = "2.1.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "6BDEA95248093599391C3B5DF1835C5C6A86C353C2F99CE539B450E3432FE117" }, + { name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" }, + { name = "gleam_community_ansi", version = "1.5.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_regexp", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "B5AA433AF84313E23FDF90CCFF752B9380FE9FFCE02B2949D49B7AACCC77B16D" }, + { name = "gleam_community_colour", version = "2.0.4", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "6DB4665555D7D2B27F0EA32EF47E8BEBC4303821765F9C73D483F38EE24894F0" }, + { name = "gleam_crypto", version = "1.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "2DE9E4EF53CF6FEE049D4F765731F7178F7A11AEFAE00EEE63BF7536B354AD3F" }, + { name = "gleam_erlang", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "1124AD3AA21143E5AF0FC5CF3D9529F6DB8CA03E43A55711B60B6B7B3874375C" }, + { name = "gleam_fetch", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_http", "gleam_javascript", "gleam_stdlib"], otp_app = "gleam_fetch", source = "hex", outer_checksum = "284CE88E37436699545F9F65D413E1DFB6C1EA3FE3824B6EA2018D0ECF088FFC" }, + { name = "gleam_http", version = "4.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "82EA6A717C842456188C190AFB372665EA56CE13D8559BF3B1DD9E40F619EE0C" }, + { name = "gleam_httpc", version = "5.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gleam_httpc", source = "hex", outer_checksum = "C545172618D07811494E97AAA4A0FB34DA6F6D0061FDC8041C2F8E3BE2B2E48F" }, + { name = "gleam_javascript", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_javascript", source = "hex", outer_checksum = "D542C4B4F40E942F5D3372D524419FA521A7BB92D621AF696CC286E89D882D55" }, + { name = "gleam_json", version = "3.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "44FDAA8847BE8FC48CA7A1C089706BD54BADCC4C45B237A992EDDF9F2CDB2836" }, + { name = "gleam_otp", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "DE4CA6850842F0266EE95317A25DD6A0A0F20CDFAB7C0ADC2E63251D7C3C72EC" }, + { name = "gleam_regexp", version = "1.1.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "9C215C6CA84A5B35BB934A9B61A9A306EC743153BE2B0425A0D032E477B062A9" }, + { name = "gleam_stdlib", version = "1.0.5", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "CEE5B6C076A85B45F60C585F4316C63EC8B7127C119D5738C3958A9C4D50404E" }, + { name = "gleam_time", version = "1.10.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_time", source = "hex", outer_checksum = "56539216E4C4B1748714652AB38F0BD16B9101F61DB62769FDC7CD42A8E5E833" }, + { name = "gleeunit", version = "1.11.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "EC31ABA74256AEA531EDF8169931D775BBB384FED0A8A1BDC4DD9354E3E21826" }, + { name = "glint", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_community_colour", "gleam_stdlib", "snag"], otp_app = "glint", source = "hex", outer_checksum = "26CCA9BC3ACB56CD9D754ACF598F49B4C281C4FDD81AE61FA21C8E92E9C8218E" }, + { name = "glisten", version = "9.0.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib", "logging"], otp_app = "glisten", source = "hex", outer_checksum = "7795AA50830656F3A0316A6B26595F893C83272DA901B3405E31339CAA31A10B" }, + { name = "gramps", version = "6.0.1", build_tools = ["gleam"], requirements = ["gleam_crypto", "gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gramps", source = "hex", outer_checksum = "D55636072DEE173F6586A5679D3C02EC7A0DE3F8646B78C351B72908FF223DF7" }, + { name = "group_registry", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib"], otp_app = "group_registry", source = "hex", outer_checksum = "BC798A53D6F2406DB94E27CB45C57052CB56B32ACF7CC16EA20F6BAEC7E36B90" }, + { name = "houdini", version = "1.2.1", build_tools = ["gleam"], requirements = [], otp_app = "houdini", source = "hex", outer_checksum = "6F8AC2F12974567FB744BEA66AC93CEB76AAEA19AD28564623F76CDA9BC26A85" }, + { name = "hpack_erl", version = "0.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "hpack", source = "hex", outer_checksum = "D6137D7079169D8C485C6962DFE261AF5B9EF60FBC557344511C1E65E3D95FB0" }, + { name = "justin", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "justin", source = "hex", outer_checksum = "8B1C62269E8607D0A0ED698B7903984CE0BF7B6B3C0DEA3C6C8302B39402837B" }, + { name = "logging", version = "1.5.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "logging", source = "hex", outer_checksum = "BC5F18CE5DD9686100229FE5409BDC3DD5C46D5A7DF2F804AD2D8F0DD6C5060E" }, + { name = "lustre", version = "5.7.1", build_tools = ["gleam"], requirements = ["exception", "gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib", "houdini"], otp_app = "lustre", source = "hex", outer_checksum = "663A2D1A3458914CA537A42AC07E601DD3FD85415EBDAF4717F2DFF6E86F90F9" }, + { name = "lustre_dev_tools", version = "2.3.6", build_tools = ["gleam"], requirements = ["argv", "booklet", "filepath", "gleam_community_ansi", "gleam_crypto", "gleam_erlang", "gleam_http", "gleam_httpc", "gleam_json", "gleam_otp", "gleam_regexp", "gleam_stdlib", "glint", "group_registry", "justin", "lustre", "mist", "polly", "simplifile", "tom", "wisp"], otp_app = "lustre_dev_tools", source = "hex", outer_checksum = "7A650A107C7E767D902A8CB608460B927DE0CDD47D5BA04DED71F9F622FE6AD9" }, + { name = "marceau", version = "1.3.0", build_tools = ["gleam"], requirements = [], otp_app = "marceau", source = "hex", outer_checksum = "2D1C27504BEF45005F5DFB18591F8610FB4BFA91744878210BDC464412EC44E9" }, + { name = "mist", version = "6.0.3", build_tools = ["gleam"], requirements = ["exception", "gleam_erlang", "gleam_http", "gleam_otp", "gleam_stdlib", "glisten", "gramps", "hpack_erl", "logging"], otp_app = "mist", source = "hex", outer_checksum = "1B07F321D5FA0CB162D81496F2DE96AEB6EF8980F4F38230A4CC3F849497E020" }, + { name = "platform", version = "1.0.0", build_tools = ["gleam"], requirements = [], otp_app = "platform", source = "hex", outer_checksum = "8339420A95AD89AAC0F82F4C3DB8DD401041742D6C3F46132A8739F6AEB75391" }, + { name = "plinth", version = "0.11.0", build_tools = ["gleam"], requirements = ["gleam_javascript", "gleam_json", "gleam_stdlib"], otp_app = "plinth", source = "hex", outer_checksum = "D30FDE8FC11EB76538AB498ACFF5399D0AE27993C74D63BE05AFE8CE80C4C839" }, + { name = "polly", version = "3.1.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_erlang", "gleam_otp", "gleam_stdlib", "simplifile"], otp_app = "polly", source = "hex", outer_checksum = "51FB565D81FF6212FDF3306D44419601F2A7C4EDD1F00FC9DA5C376A00AED4FE" }, + { name = "rsvp", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_fetch", "gleam_http", "gleam_httpc", "gleam_javascript", "gleam_json", "gleam_stdlib", "lustre"], otp_app = "rsvp", source = "hex", outer_checksum = "A38F2DB9657E84A584278DB50FD903693FF370C22C191753B773546FEB2465F0" }, + { name = "shared", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], source = "local", path = "../shared" }, + { name = "simplifile", version = "2.7.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "A2727627B063E87351934C7F7F008F2D1FDB16F6DE0B8C79F9E46459CFC9C164" }, + { name = "snag", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "snag", source = "hex", outer_checksum = "274F41D6C3ECF99F7686FDCE54183333E41D2C1CA5A3A673F9A8B2C7A4401077" }, + { name = "tom", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_time"], otp_app = "tom", source = "hex", outer_checksum = "DCF04CB7AB35D58CFC598C66EA2E1816D160759802C89B2BA6238780D59BC256" }, + { name = "wisp", version = "2.2.2", build_tools = ["gleam"], requirements = ["directories", "exception", "filepath", "gleam_crypto", "gleam_erlang", "gleam_http", "gleam_json", "gleam_stdlib", "houdini", "logging", "marceau", "mist", "simplifile"], otp_app = "wisp", source = "hex", outer_checksum = "5FF5F1E288C3437252ABB93D8F9CF42FF652CE7AD54480CFE736038DC09C4F22" }, +] + +[requirements] +gleam_erlang = { version = ">= 1.3.0 and < 2.0.0" } +gleam_http = { version = ">= 4.3.0 and < 5.0.0" } +gleam_json = { version = ">= 3.1.0 and < 4.0.0" } +gleam_stdlib = { version = ">= 1.0.0 and < 2.0.0" } +gleeunit = { version = ">= 1.0.0 and < 2.0.0" } +lustre = { version = ">= 5.7.1 and < 6.0.0" } +lustre_dev_tools = { version = ">= 2.3.6 and < 3.0.0" } +mist = { version = ">= 6.0.3 and < 7.0.0" } +plinth = { version = ">= 0.11.0 and < 1.0.0" } +rsvp = { version = ">= 2.0.0 and < 3.0.0" } +shared = { path = "../shared" } +simplifile = { version = ">= 2.7.0 and < 3.0.0" } diff --git a/client/src/client.gleam b/client/src/client.gleam new file mode 100644 index 0000000..dc4f0a7 --- /dev/null +++ b/client/src/client.gleam @@ -0,0 +1,435 @@ +import gleam/int +import gleam/list +import gleam/option.{type Option, None, Some} +import gleam/result +import lustre +import lustre/attribute +import lustre/effect.{type Effect} +import lustre/element.{type Element} +import lustre/element/html +import lustre/event +import plinth/browser/location +import plinth/browser/window +import rsvp +import shared + +pub fn main() -> Nil { + let app = lustre.application(init, update, view) + let assert Ok(_) = lustre.start(app, "#app", None) + Nil +} + +type Model { + Model( + page: String, + dashboard: Option(shared.Dashboard), + error: Option(String), + username: String, + password: String, + project_name: String, + project_description: String, + task_title: String, + task_description: String, + task_assignee: String, + task_assignees: String, + task_due_date: String, + ) +} + +pub type Message { + DashboardLoaded(Result(shared.Dashboard, rsvp.Error(String))) + LoginSubmitted(List(#(String, String))) + RegisterSubmitted(List(#(String, String))) + ProjectSubmitted(List(#(String, String))) + TaskSubmitted(Int, List(#(String, String))) + StatusSubmitted(Int, List(#(String, String))) + Authenticated(Result(String, rsvp.Error(String))) + Saved(Result(String, rsvp.Error(String))) + UsernameChanged(String) + PasswordChanged(String) + ProjectNameChanged(String) + ProjectDescriptionChanged(String) + TaskTitleChanged(String) + TaskDescriptionChanged(String) + TaskAssigneeChanged(String) + TaskAssigneesChanged(String) + TaskDueDateChanged(String) + LogOut + Nothing +} + +fn init(_flags: Option(Nil)) -> #(Model, Effect(Message)) { + let page = case current_path() { + "/login" -> "login" + "/register" -> "register" + _ -> "dashboard" + } + + echo page + let model = + Model( + page:, + dashboard: None, + error: None, + username: "", + password: "", + project_name: "", + project_description: "", + task_title: "", + task_description: "", + task_assignee: "", + task_assignees: "", + task_due_date: "", + ) + + case page { + // "dashboard" -> + // #( + // model, + // rsvp.get( + // "/api/dashboard", + // rsvp.expect_json(shared.dashboard_decoder(), DashboardLoaded), + // ), + // ) + _ -> + //#(model, effect.none()) + auth_request(model, [], "/api/login", "/") + } +} + +fn update(model: Model, message: Message) -> #(Model, Effect(Message)) { + case message { + DashboardLoaded(Ok(value)) -> { + echo "dashload good" + #(Model(..model, dashboard: Some(value), error: None), effect.none()) + } + DashboardLoaded(Error(_)) -> { + echo "dashload err" + #( + Model( + ..model, + page: "login", + error: Some("Please sign in to continue."), + ), + effect.none(), + ) + } + UsernameChanged(value) -> #(Model(..model, username: value), effect.none()) + PasswordChanged(value) -> #(Model(..model, password: value), effect.none()) + ProjectNameChanged(value) -> #( + Model(..model, project_name: value), + effect.none(), + ) + ProjectDescriptionChanged(value) -> #( + Model(..model, project_description: value), + effect.none(), + ) + TaskTitleChanged(value) -> #( + Model(..model, task_title: value), + effect.none(), + ) + TaskDescriptionChanged(value) -> #( + Model(..model, task_description: value), + effect.none(), + ) + TaskAssigneeChanged(value) -> #( + Model(..model, task_assignee: value), + effect.none(), + ) + TaskAssigneesChanged(value) -> #( + Model(..model, task_assignees: value), + effect.none(), + ) + TaskDueDateChanged(value) -> #( + Model(..model, task_due_date: value), + effect.none(), + ) + LoginSubmitted(fields) -> auth_request(model, fields, "/api/login", "/") + RegisterSubmitted(fields) -> + auth_request(model, fields, "/api/register", "/") + ProjectSubmitted(fields) -> { + let body = + shared.NewProject(field(fields, "name"), field(fields, "description")) + |> shared.new_project_json + #( + model, + rsvp.post( + "/api/projects", + body, + rsvp.expect_any_response(fn(result) { + Saved(result |> result.map(fn(response) { response.body })) + }), + ), + ) + } + TaskSubmitted(project_id, fields) -> { + let body = + shared.NewTask( + field(fields, "title"), + field(fields, "description"), + field(fields, "assignee"), + field(fields, "assignees"), + field(fields, "due_date"), + ) + |> shared.new_task_json + #( + model, + rsvp.post( + "/api/projects/" <> int.to_string(project_id) <> "/tasks", + body, + rsvp.expect_any_response(fn(result) { + Saved(result |> result.map(fn(response) { response.body })) + }), + ), + ) + } + StatusSubmitted(task_id, fields) -> { + let status = field(fields, "status") + let body = shared.StatusChange(status) |> shared.status_change_json + #( + model, + rsvp.post( + "/api/tasks/" <> int.to_string(task_id) <> "/status", + body, + rsvp.expect_any_response(fn(result) { + Saved(result |> result.map(fn(response) { response.body })) + }), + ), + ) + } + Authenticated(Ok(_)) -> #( + Model(..model, page: "dashboard"), + rsvp.get( + "/api/dashboard", + rsvp.expect_json(shared.dashboard_decoder(), DashboardLoaded), + ), + ) + Authenticated(Error(_)) -> #( + Model(..model, error: Some("Invalid username or password.")), + effect.none(), + ) + Saved(Ok(_)) -> #( + Model( + ..model, + project_name: "", + project_description: "", + task_title: "", + task_description: "", + task_assignee: "", + task_assignees: "", + task_due_date: "", + ), + rsvp.get( + "/api/dashboard", + rsvp.expect_json(shared.dashboard_decoder(), DashboardLoaded), + ), + ) + Saved(Error(_)) -> #( + Model(..model, error: Some("The request could not be saved.")), + effect.none(), + ) + LogOut -> #( + Model(..model, page: "login"), + rsvp.get("/api/logout", rsvp.expect_ok_response(fn(_) { Nothing })), + ) + Nothing -> #(model, effect.none()) + } +} + +fn auth_request( + model: Model, + fields: List(#(String, String)), + url: String, + _redirect: String, +) -> #(Model, Effect(Message)) { + let body = + shared.Credentials(field(fields, "username"), field(fields, "password")) + |> shared.credentials_json + #( + model, + rsvp.post( + url, + body, + rsvp.expect_any_response(fn(result) { + Authenticated(result |> result.map(fn(response) { response.body })) + }), + ), + ) +} + +fn view(model: Model) -> Element(Message) { + case model.page { + "login" -> auth_view(model, "Welcome back", "Log in", LoginSubmitted) + "register" -> + auth_view( + model, + "Create your account", + "Create account", + RegisterSubmitted, + ) + _ -> dashboard_view(model) + } +} + +fn auth_view( + model: Model, + title: String, + submit: String, + on_submit: fn(List(#(String, String))) -> Message, +) -> Element(Message) { + let link = case submit == "Log in" { + True -> "/register" + False -> "/login" + } + let link_text = case submit == "Log in" { + True -> "Need an account?" + False -> "Already registered?" + } + html.main([attribute.class("auth")], [ + styles(), + html.text("FRC 972 · IRON CLAW"), + html.h1([], [html.text(title)]), + html.p([], [html.text("google sheets, more like shmoogle shits")]), + error_view(model.error), + html.form([event.on_submit(on_submit)], [ + html.input([ + attribute.name("username"), + attribute.placeholder("Username"), + event.on_input(UsernameChanged), + ]), + html.input([ + attribute.name("password"), + attribute.type_("password"), + attribute.placeholder("Password"), + event.on_input(PasswordChanged), + ]), + html.button([], [html.text(submit)]), + ]), + html.a([attribute.href(link)], [html.text(link_text)]), + ]) +} + +fn dashboard_view(model: Model) -> Element(Message) { + case model.dashboard { + None -> + html.main([attribute.class("auth")], [ + html.h1([], [html.text("Loading Iron Claw...")]), + error_view(model.error), + ]) + Some(board) -> + html.main( + [attribute.class("page")], + list.append( + [ + styles(), + html.header([], [ + html.div([], [ + html.text("FRC 972 · IRON CLAW"), + html.h1([], [html.text("Team board")]), + ]), + html.button([event.on_click(LogOut)], [ + html.text("Sign out"), + ]), + ]), + html.section([attribute.class("hero")], [ + html.text("wassup"), + ]), + html.section([attribute.class("panel")], [ + html.h2([], [html.text("New project")]), + html.form([event.on_submit(ProjectSubmitted)], [ + text_input("name", "Project name"), + text_input("description", "What does success look like?"), + html.button([], [html.text("Add project")]), + ]), + ]), + ], + list.map(board.projects, fn(project) { project_view(model, project) }), + ), + ) + } +} + +fn project_view(_model: Model, project: shared.Project) -> Element(Message) { + html.article( + [attribute.class("panel")], + list.append( + [ + html.text("PROJECT"), + html.h2([], [html.text(project.name)]), + html.p([], [html.text(project.description)]), + ], + list.append(list.map(project.tasks, task_view), [ + html.form( + [event.on_submit(fn(fields) { TaskSubmitted(project.id, fields) })], + [ + text_input("title", "Task title"), + text_input("assignee", "Owner"), + text_input("assignees", "Assignees"), + text_input("due_date", "Due date"), + text_input("description", "Details"), + html.button([], [html.text("Add task")]), + ], + ), + ]), + ), + ) +} + +fn task_view(task: shared.Task) -> Element(Message) { + let next = case task.status { + "todo" -> "doing" + "doing" -> "done" + _ -> "todo" + } + html.div([attribute.class("task")], [ + html.div([], [ + html.strong([], [html.text(task.title)]), + html.p([], [html.text(task.description)]), + ]), + html.div([attribute.class("task-meta")], [ + html.span([], [html.text(task.status)]), + html.text("Owner: " <> task.assignee), + html.text("Assignees: " <> task.assignees), + html.form( + [event.on_submit(fn(fields) { StatusSubmitted(task.id, fields) })], + [ + html.input([ + attribute.type_("hidden"), + attribute.name("status"), + attribute.value(next), + ]), + html.button([], [html.text("Move to " <> next)]), + ], + ), + ]), + ]) +} + +fn text_input(name: String, placeholder: String) -> Element(Message) { + html.input([ + attribute.name(name), + attribute.placeholder(placeholder), + ]) +} + +fn styles() -> Element(Message) { + html.style( + [], + "body{margin:0;background:#f4f0e8;color:#28231e;font-family:Inter,ui-sans-serif,system-ui,sans-serif}.page{max-width:1120px;margin:auto;padding:28px 22px 72px}.auth{max-width:430px;margin:10vh auto;padding:42px;background:#fff;border:1px solid #e2d9cc;border-radius:22px;box-shadow:0 20px 60px #2d241414}.auth h1{font-size:clamp(2.4rem,8vw,4.8rem);line-height:.95;letter-spacing:-.06em;margin:14px 0}.auth form{display:grid;gap:12px;margin:26px 0 14px}.auth a{color:#b53b24;font-weight:700}.eyebrow{font-size:.72rem;letter-spacing:.16em;color:#b53b24;font-weight:800}header{display:flex;justify-content:space-between;gap:24px;align-items:start;margin-bottom:42px}header h1{font-size:clamp(2.7rem,7vw,5.5rem);line-height:.9;letter-spacing:-.07em;margin:12px 0}.hero{padding:42px;border-radius:22px;background:linear-gradient(120deg,#29241f,#594538);color:#fff;margin-bottom:20px;font-size:clamp(1.5rem,3vw,2.5rem);font-weight:800;letter-spacing:-.04em}.panel{background:#fff;border:1px solid #e2d9cc;border-radius:18px;padding:24px;margin:18px 0;box-shadow:0 12px 30px #2d24140b}.panel h2{margin:5px 0 8px;letter-spacing:-.03em}.panel>p{color:#796f64}.task{display:flex;justify-content:space-between;gap:20px;padding:17px 0;border-top:1px solid #eee8df}.task p{margin:5px 0 0;color:#796f64}.task-meta{display:flex;align-items:center;justify-content:flex-end;gap:9px;flex-wrap:wrap;color:#796f64;font-size:.82rem}.task-meta span{padding:5px 9px;border-radius:99px;background:#f0ebe3}.task-meta button{padding:7px 10px;font-size:.78rem}form{display:flex;gap:10px;flex-wrap:wrap;margin-top:22px}input{min-width:150px;flex:1;padding:12px 13px;border:1px solid #d9cfc2;border-radius:10px;background:#fffcf8;color:#28231e;font:inherit}button{border:0;border-radius:10px;background:#b53b24;color:#fff;padding:12px 17px;font:inherit;font-weight:800;cursor:pointer}button:hover{background:#902e1d}.error{color:#b53b24;font-weight:700}a{color:inherit;text-decoration:none}@media(max-width:650px){.task{display:block}.task-meta{justify-content:flex-start;margin-top:12px}header{display:block}.hero{padding:28px}}", + ) +} + +fn error_view(error: Option(String)) -> Element(Message) { + case error { + Some(message) -> html.p([attribute.class("error")], [html.text(message)]) + None -> element.none() + } +} + +fn field(fields: List(#(String, String)), name: String) -> String { + list.key_find(fields, name) |> result.unwrap("") +} + +fn current_path() -> String { + window.self() |> window.location |> location.pathname +} diff --git a/client/static/cat.png b/client/static/cat.png new file mode 100644 index 0000000000000000000000000000000000000000..6c4c3ab3334310cfb8e636ebda5fd0a740758922 GIT binary patch literal 65460 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ξHdO_ZHtx#Wa8uqc;UpP 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 s?qv>d)2XD^!$mb2e57 Nil { + gleeunit.main() +} + +// gleeunit test functions end in `_test` +pub fn hello_world_test() { + let name = "Joe" + let greeting = "Hello, " <> name <> "!" + + assert greeting == "Hello, Joe!" +} diff --git a/css_to_lustre/.gitignore b/css_to_lustre/.gitignore new file mode 100644 index 0000000..599be4e --- /dev/null +++ b/css_to_lustre/.gitignore @@ -0,0 +1,4 @@ +*.beam +*.ez +/build +erl_crash.dump diff --git a/css_to_lustre/README.md b/css_to_lustre/README.md new file mode 100644 index 0000000..7db8101 --- /dev/null +++ b/css_to_lustre/README.md @@ -0,0 +1,24 @@ +# css_to_lustre + +[![Package Version](https://img.shields.io/hexpm/v/css_to_lustre)](https://hex.pm/packages/css_to_lustre) +[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://css-to-lustre.hexdocs.pm/) + +```sh +gleam add css_to_lustre@1 +``` +```gleam +import css_to_lustre + +pub fn main() -> Nil { + // TODO: An example of the project in use +} +``` + +Further documentation can be found at . + +## Development + +```sh +gleam run # Run the project +gleam test # Run the tests +``` diff --git a/css_to_lustre/gleam.toml b/css_to_lustre/gleam.toml new file mode 100644 index 0000000..9d4a62f --- /dev/null +++ b/css_to_lustre/gleam.toml @@ -0,0 +1,20 @@ +name = "css_to_lustre" +version = "1.0.0" + +# Fill out these fields if you intend to generate HTML documentation or publish +# your project to the Hex package manager. +# +# description = "" +# licences = ["Apache-2.0"] +# repository = { type = "github", user = "", repo = "" } +# links = [{ title = "Website", href = "" }] +# +# For a full reference of all the available options, you can have a look at +# https://gleam.run/writing-gleam/gleam-toml/. + +[dependencies] +gleam_stdlib = ">= 1.0.0 and < 2.0.0" +in = ">= 1.1.0 and < 2.0.0" + +[dev_dependencies] +gleeunit = ">= 1.0.0 and < 2.0.0" diff --git a/css_to_lustre/manifest.toml b/css_to_lustre/manifest.toml new file mode 100644 index 0000000..a0b9502 --- /dev/null +++ b/css_to_lustre/manifest.toml @@ -0,0 +1,18 @@ +# Do not manually edit this file, it is managed by Gleam. +# +# This file locks the dependency versions used, to make your build +# deterministic and to prevent unexpected versions from being included +# in your application. +# +# You should check this file into your source control repository. + +packages = [ + { name = "gleam_stdlib", version = "1.0.5", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "CEE5B6C076A85B45F60C585F4316C63EC8B7127C119D5738C3958A9C4D50404E" }, + { name = "gleeunit", version = "1.11.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "EC31ABA74256AEA531EDF8169931D775BBB384FED0A8A1BDC4DD9354E3E21826" }, + { name = "in", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "in", source = "hex", outer_checksum = "5339494529936AF83EAA0B8368195DCA9505382836CDED4CD6B0F5F9FA93C2B8" }, +] + +[requirements] +gleam_stdlib = { version = ">= 1.0.0 and < 2.0.0" } +gleeunit = { version = ">= 1.0.0 and < 2.0.0" } +in = { version = ">= 1.1.0 and < 2.0.0" } diff --git a/css_to_lustre/src/css_to_lustre.gleam b/css_to_lustre/src/css_to_lustre.gleam new file mode 100644 index 0000000..6dccda7 --- /dev/null +++ b/css_to_lustre/src/css_to_lustre.gleam @@ -0,0 +1,41 @@ +import gleam/list +import gleam/option.{type Option, None, Some} +import gleam/string +import in + +pub fn main() -> Nil { + let lines = lines() |> list.map(string.drop_end(_, 1)) + echo lines + + let pairs = lines |> list.map(line_to_css_pair) |> option.values + + let fmt = echo pairs |> list.map(lustre_format) |> string.concat + + Nil +} + +fn lustre_format(pair: #(String, String)) -> String { + "#(" <> pair.0 <> "," <> pair.1 <> ")," +} + +fn line_to_css_pair(line: String) -> Option(#(String, String)) { + use #(key, value) <- option.map( + line |> string.trim |> string.split_once(":") |> option.from_result, + ) + + let key = string.trim(key) + let value = value |> string.trim |> string.remove_suffix(";") + + #(key, value) +} + +fn lines() -> List(String) { + read_lines([]) +} + +fn read_lines(acc: List(String)) -> List(String) { + case in.read_line() { + Ok(line) -> read_lines([line, ..acc]) + Error(_) -> list.reverse(acc) + } +} diff --git a/css_to_lustre/test/css_to_lustre_test.gleam b/css_to_lustre/test/css_to_lustre_test.gleam new file mode 100644 index 0000000..fba3c88 --- /dev/null +++ b/css_to_lustre/test/css_to_lustre_test.gleam @@ -0,0 +1,13 @@ +import gleeunit + +pub fn main() -> Nil { + gleeunit.main() +} + +// gleeunit test functions end in `_test` +pub fn hello_world_test() { + let name = "Joe" + let greeting = "Hello, " <> name <> "!" + + assert greeting == "Hello, Joe!" +} diff --git a/server/.env b/server/.env new file mode 100644 index 0000000..5f11e7b --- /dev/null +++ b/server/.env @@ -0,0 +1 @@ +DATABASE_URL="postgresql://robotics:reallylongamazingpasswordbyyourstruly@taranathan.com:5432/robotics_task_manager" diff --git a/server/.gitignore b/server/.gitignore new file mode 100644 index 0000000..599be4e --- /dev/null +++ b/server/.gitignore @@ -0,0 +1,4 @@ +*.beam +*.ez +/build +erl_crash.dump diff --git a/server/README.md b/server/README.md new file mode 100644 index 0000000..abe3858 --- /dev/null +++ b/server/README.md @@ -0,0 +1,32 @@ +# Iron Claw task board + +The server is a small Gleam/Wisp JSON API for FRC team 972. The Lustre client +in `../client` owns the UI and communicates with this server through the typed +models in `../shared`. It stores users, projects, tasks, and signed sessions in +PostgreSQL. SQL query modules live in `src/sql.gleam`; the corresponding SQL +source files in `src/sql/` are kept ready for Squirrel generation. + +## Run locally + +Create a PostgreSQL database, then export a connection string: + +```sh +export DATABASE_URL=postgresql://postgres:postgres@localhost:5432/iron_claw +export SESSION_SECRET="replace-this-in-production" +gleam run +``` + +The `db/init.sql` schema is applied automatically at startup. Build the client +bundle before starting the server: + +```sh +cd ../client +gleam run -m lustre/dev build +cp dist/client.js ../server/static/client.js +``` + +Then open to create the first account. + +Run the test suite with `gleam test`. If the database schema changes, run +`gleam run -m squirrel` with the same `DATABASE_URL` to regenerate the typed +query module. diff --git a/server/data.json b/server/data.json new file mode 100644 index 0000000..c7f173a --- /dev/null +++ b/server/data.json @@ -0,0 +1 @@ +[{"secret_word":"'squire","clues":[{"next":"and the 'squire","previous":"preaching at the","count":4},{"next":"who live in","previous":"parson and the","count":4},{"next":"to be revenged","previous":"'squire and the","count":4},{"next":"shall make you","previous":"a polite country","count":3},{"next":"has not said","previous":"extremity that the","count":3},{"next":"with the parson","previous":"a hearty english","count":2},{"next":"and the whole","previous":"book against the","count":2},{"next":"lath a proper","previous":"other hand there's","count":2},{"next":"or a conjurer","previous":"coquet a country","count":2},{"next":"of shrubs who","previous":"of interrogating the","count":1},{"next":"has said it","previous":"not priest or","count":1},{"next":"of dames' in","previous":"have turned a","count":1},{"next":"said he you","previous":"i told you","count":1}]},{"secret_word":"'your","clues":[{"next":"most humble servant","previous":"'i am sir","count":21},{"next":"most humble servant","previous":"am dear sir","count":12},{"next":"most humble servant","previous":"and in particular","count":2},{"next":"money or your","previous":"the girl gloomily","count":1},{"next":"voice sounds as","previous":"the elder woman","count":1},{"next":"husband' or 'mr","previous":"suddenly call bruce","count":1},{"next":"royal highness is","previous":"replied without reflection","count":1},{"next":"telling me that","previous":"' he said","count":1},{"next":"face is the","previous":"' he observed","count":1},{"next":"leaving us at","previous":"' said wentworth","count":1},{"next":"ladyship i am","previous":"sarcastic smile saying","count":1},{"next":"chancellor judges like","previous":"treachery' wallenstein replies","count":1}]},{"secret_word":"action","clues":[{"next":"to the word","previous":"and suiting the","count":26},{"next":"always pressing then","previous":"the need for","count":1},{"next":"and that at","previous":"he must have","count":1},{"next":"pressed upon him","previous":"some great immediate","count":1},{"next":"all along the","previous":"anything like gettin'","count":1},{"next":"on my stuff","previous":"you to get","count":1},{"next":"those westerners are","previous":"brightest people to","count":1},{"next":"and there couldn't","previous":"reason for prompt","count":1},{"next":"is matured he","previous":"unusual plan of","count":1},{"next":"and i'm going","previous":"get things in","count":1},{"next":"resumed her tete","previous":"performed a kindly","count":1},{"next":"and set the","previous":"swing out get","count":1}]},{"secret_word":"aine","clues":[{"next":"had just gone","previous":"very early risler","count":3},{"next":"come in on","previous":"they see risler","count":3},{"next":"would ask nothing","previous":"sure monsieur risler","count":3},{"next":"by absenting herself","previous":"insult madame risler","count":3},{"next":"and the factory","previous":"talks about risler","count":3},{"next":"of rue des","previous":"jeune and risler","count":3},{"next":"was awakened with","previous":"jeune and risler","count":3},{"next":"sigismond planus is","previous":"jeune and risler","count":3},{"next":"has the appearance","previous":"fromont jeune risler","count":3},{"next":"whom she had","previous":"planus recognize risler","count":3},{"next":"marked the beginning","previous":"jeune et risler","count":1},{"next":"crowned by the","previous":"jeune et risler","count":1},{"next":"enjoyed a notable","previous":"jeune et risler","count":1}]},{"secret_word":"albertinelli","clues":[{"next":"at a time","previous":"by cardinal giulio","count":3},{"next":"a little of","previous":"and of prince","count":3},{"next":"prided himself on","previous":"and whom prince","count":3},{"next":"professor arrighi choulette","previous":"of the prince","count":3},{"next":"della spina she","previous":"to prince eusebio","count":3},{"next":"caressed his beard","previous":"over her prince","count":3},{"next":"and that gentle","previous":"too handsome prince","count":3},{"next":"palace said miss","previous":"come to the","count":3},{"next":"coming out of","previous":"bell and prince","count":3},{"next":"will read to","previous":"punish you prince","count":3},{"next":"gravely you are","previous":"choulette said prince","count":3},{"next":"how do you","previous":"dechartre asked prince","count":3}]},{"secret_word":"aldarondo","clues":[{"next":"charles franks and","previous":"produced by charles","count":10},{"next":"tiffany vergon william","previous":"produced by charles","count":2},{"next":"and the online","previous":"charles franks charles","count":2},{"next":"mary meehan and","previous":"produced by charles","count":1},{"next":"tiffany vergon and","previous":"produced by charles","count":1},{"next":"tiffany vergon robert","previous":"produced by charles","count":1},{"next":"tiffany vergon thomas","previous":"produced by charles","count":1},{"next":"tiffany vergon juliet","previous":"produced by charles","count":1},{"next":"tiffany vergon s","previous":"produced by charles","count":1},{"next":"tiffany vergon charles","previous":"produced by charles","count":1},{"next":"tiffany vergon david","previous":"produced by charles","count":1},{"next":"tiffany vergon jerry","previous":"produced by charles","count":1},{"next":"tiffany vergon eric","previous":"produced by charles","count":1},{"next":"tiffany vergon andy","previous":"produced by charles","count":1},{"next":"tiffany vergon michelle","previous":"produced by charles","count":1},{"next":"tiffany vergon thomas","previous":"prepared by charles","count":1},{"next":"charles franks and","previous":"van dael charles","count":1},{"next":"charles franks and","previous":"tom allen charles","count":1},{"next":"charles franks and","previous":"tonya allen charles","count":1}]},{"secret_word":"arbillot","clues":[{"next":"the notary announcing","previous":"second missive from","count":3},{"next":"replied the justice","previous":"your orders maitre","count":3},{"next":"we will not","previous":"you please maitre","count":3},{"next":"the notary passed","previous":"before their departure","count":3},{"next":"has been speaking","previous":"mother nor maitre","count":3},{"next":"the notary i","previous":"intention to monsieur","count":3},{"next":"and ask him","previous":"morrow to monsieur","count":3},{"next":"and it seems","previous":"confidence in maitre","count":3},{"next":"is drawn up","previous":"inventory explained maitre","count":3},{"next":"which was dignified","previous":"conferring with maitre","count":3},{"next":"and the tax","previous":"clerk seurrot maitre","count":3},{"next":"and a petulant","previous":"bailiff entered maitre","count":3},{"next":"drew up the","previous":"auberive where maitre","count":3}]},{"secret_word":"arcis","clues":[{"next":"beatrix a man","previous":"the member for","count":9},{"next":"cousin betty the","previous":"the member for","count":7},{"next":"a daughter of","previous":"the member for","count":4},{"next":"serizy comtesse de","previous":"the member for","count":4},{"next":"pamiers vidame de","previous":"the member for","count":3},{"next":"falcon jean the","previous":"the member for","count":2},{"next":"ridal fulgence a","previous":"the member for","count":2},{"next":"langeais duc de","previous":"the member for","count":2},{"next":"navarreins duc de","previous":"the member for","count":2},{"next":"milaud lost illusions","previous":"the member for","count":2},{"next":"michu francois the","previous":"the member for","count":2},{"next":"bruel jean francois","previous":"the member for","count":1}]},{"secret_word":"ardea","clues":[{"next":"amused himself by","previous":"and increasing vexation","count":3},{"next":"and on finding","previous":"the engagement of","count":3},{"next":"and in thus","previous":"in selling up","count":3},{"next":"and hafner rendered","previous":"his impatience toward","count":3},{"next":"and others circulated","previous":"her friends hafner","count":3},{"next":"had jested so","previous":"on which imprudent","count":3},{"next":"and he did","previous":"little dealing to","count":3},{"next":"and fanny hafner","previous":"honor of peppino","count":3},{"next":"for the emotion","previous":"fancied she loved","count":3},{"next":"alas i am","previous":"begins to judge","count":3},{"next":"try to see","previous":"cibo pietrapertosa hafner","count":3},{"next":"lanuvium and the","previous":"right stretching to","count":1}]},{"secret_word":"armholes","clues":[{"next":"of his waistcoat","previous":"thumbs in the","count":11},{"next":"of his vest","previous":"thumbs into the","count":6},{"next":"of his waistcoat","previous":"thumbs into the","count":5},{"next":"of his vest","previous":"thumbs in the","count":4},{"next":"of his waistcoat","previous":"by the two","count":1},{"next":"of his vest","previous":"were in the","count":1},{"next":"of his vest","previous":"hands in the","count":1},{"next":"of his vest","previous":"fingers in the","count":1},{"next":"of his waistcoat","previous":"fingers in the","count":1},{"next":"of the waistcoat","previous":"thumbs in the","count":1},{"next":"of his broad","previous":"thumbs in the","count":1},{"next":"of his execrable","previous":"thumbs in the","count":1},{"next":"watched the wife","previous":"thumbs in his","count":1},{"next":"regarding dunham quizzically","previous":"thumbs in his","count":1},{"next":"of his waistcoat","previous":"thumbs within the","count":1},{"next":"of his waistcoat","previous":"comfortably in the","count":1},{"next":"and showed at","previous":"tight about the","count":1},{"next":"of which his","previous":"waistcoat in the","count":1}]},{"secret_word":"astika","clues":[{"next":"parva of the","previous":"section in the","count":24},{"next":"after the snake","previous":"the words of","count":1},{"next":"who saved the","previous":"of jaratkaru that","count":1},{"next":"exactly as it","previous":"this history of","count":1},{"next":"plaudits expressive of","previous":"was granted to","count":1},{"next":"born of jaratkaru","previous":"mind the famous","count":1},{"next":"exceedingly gratified for","previous":"home the wise","count":1},{"next":"shall have his","previous":"such mention of","count":1},{"next":"and asked him","previous":"much pleased with","count":1},{"next":"that increaseth virtue","previous":"holy history of","count":1},{"next":"also be gratified","previous":"safe let this","count":1},{"next":"artiman and sunitha","previous":"call to mind","count":1}]},{"secret_word":"auberive","clues":[{"next":"there will be","previous":"the gentlemen of","count":3},{"next":"at the epoch","previous":"the monks of","count":3},{"next":"people with whom","previous":"the notables of","count":3},{"next":"through the woods","previous":"their way to","count":3},{"next":"to notify the","previous":"am going to","count":3},{"next":"gentry with whom","previous":"those of the","count":3},{"next":"and ask the","previous":"go over to","count":3},{"next":"where maitre arbillot","previous":"accompanied claudet to","count":3},{"next":"side along the","previous":"shortly on the","count":3},{"next":"and had deliberately","previous":"distinguished visitors from","count":3},{"next":"society is following","previous":"reine listening the","count":3},{"next":"road and the","previous":"praslay by the","count":3},{"next":"notary's first letter","previous":"contained in the","count":2}]},{"secret_word":"author's","clues":[{"next":"ideas before making","previous":"to sample the","count":57},{"next":"powers to be","previous":"proof of the","count":2},{"next":"nature but that","previous":"or at least","count":2},{"next":"having but you","previous":"much worth the","count":2},{"next":"life assail toil","previous":"what ills the","count":2},{"next":"visage is but","previous":"frontispiece of an","count":2},{"next":"jury to determine","previous":"one of the","count":1},{"next":"school exercises we","previous":"rest of the","count":1},{"next":"copy with his","previous":"pray accept this","count":1},{"next":"friendly esteem is","previous":"mark of the","count":1},{"next":"merits they are","previous":"con of an","count":1},{"next":"name and the","previous":"celebrity of the","count":1}]},{"secret_word":"bagg","clues":[{"next":"says it was","previous":"the man laughed","count":3},{"next":"rushing in with","previous":"a dart at","count":3},{"next":"got home alive","previous":"is well that","count":3},{"next":"i have no","previous":"should do without","count":3},{"next":"though without it","previous":"nor more does","count":3},{"next":"and left the","previous":"trouble ' said","count":3},{"next":"and staring him","previous":"close up to","count":3},{"next":"'and in that","previous":"sir ' said","count":3},{"next":"and drawing himself","previous":"sir ' says","count":3},{"next":"and forthwith seized","previous":"sir ' says","count":3},{"next":"thinks at least","previous":"immense tall fellow","count":3},{"next":"says he had","previous":"grappled each other","count":3},{"next":"is a left","previous":"fellow's right eye","count":2}]},{"secret_word":"balzajette","clues":[{"next":"uneasiness for his","previous":"of the lamps","count":3},{"next":"and his return","previous":"his departure with","count":3},{"next":"talk for if","previous":"only to let","count":3},{"next":"or to the","previous":"to phillis to","count":3},{"next":"spoke of the","previous":"that moment monsieur","count":3},{"next":"replied i am","previous":"that saniel said","count":3},{"next":"a few hours","previous":"came herewith monsieur","count":3},{"next":"he was in","previous":"been to monsieur","count":3},{"next":"said who never","previous":"we have decided","count":3},{"next":"said who took","previous":"let us return","count":3},{"next":"proposed asking for","previous":"setting sun faded","count":3},{"next":"hailed a passing","previous":"des petits champs","count":3}]},{"secret_word":"barratt","clues":[{"next":"the proprietor of","previous":"the fact of","count":3},{"next":"to a shocking","previous":"of this wretched","count":3},{"next":"had attempted to","previous":"in the prison","count":3},{"next":"had practised the","previous":"to arise that","count":3},{"next":"had met her","previous":"city the monster","count":3},{"next":"and seconded by","previous":"her made by","count":3},{"next":"into such written","previous":"means of entrapping","count":3},{"next":"though perhaps it","previous":"wicked collusion with","count":3},{"next":"and accordingly much","previous":"attempted by this","count":3},{"next":"but now its","previous":"run strongly against","count":3},{"next":"did not revive","previous":"sufficiently strange that","count":3},{"next":"came to suspect","previous":"disguise his purposes","count":3},{"next":"had that been","previous":"emanating from this","count":3}]},{"secret_word":"beatrix","clues":[{"next":"a man of","previous":"member for arcis","count":9},{"next":"lost illusions a","previous":"mademoiselle felicite des","count":5},{"next":"the peasantry chesnel","previous":"the old maid","count":2},{"next":"ronceret madame du","previous":"the old maid","count":2},{"next":"leroi pierre the","previous":"the gondreville mystery","count":2},{"next":"the unconscious humorists","previous":"a courtesan's life","count":2},{"next":"gaudissart ii scherbelloff","previous":"du or duronceret","count":2},{"next":"in which she","previous":"out his novel","count":1},{"next":"and the first","previous":"last part of","count":1},{"next":"trotter a daughter","previous":"mother's name was","count":1},{"next":"ronceret madame du","previous":"antiquities companion piece","count":1},{"next":"the gondreville mystery","previous":"simeuse admiral de","count":1},{"next":"and modeste mignon","previous":"etude de femme","count":1}]},{"secret_word":"bebee","clues":[{"next":"if you want","previous":"are going mad","count":3},{"next":"screamed the girl","previous":"a pretty affair","count":3},{"next":"say that she","previous":"had heard her","count":3},{"next":"'twas by that","previous":"it romanly already","count":3},{"next":"isn't he poisoned","previous":"if he doesn't","count":3},{"next":"leave the fellow","previous":"you are mad","count":3},{"next":"let's leave him","previous":"soon be gone","count":3},{"next":"as much or","previous":"say so again","count":3},{"next":"' says the","previous":"'come with me","count":3},{"next":"ha ha look","previous":"but look there","count":2},{"next":"here's the door","previous":"your here there","count":2},{"next":"and becoming alarmed","previous":"sleep missed her","count":2}]},{"secret_word":"bigelow","clues":[{"next":"paine mt bg","previous":"biography by albert","count":11},{"next":"paine mt lt","previous":"v by albert","count":10},{"next":"house bar was","previous":"and round the","count":1},{"next":"house on the","previous":"in at the","count":1},{"next":"house to the","previous":"way from the","count":1},{"next":"and nuttall are","previous":"as long as","count":1},{"next":"house the previous","previous":"me at the","count":1},{"next":"house to make","previous":"front of the","count":1},{"next":"house for choice","previous":"main street the","count":1},{"next":"house office that","previous":"walked into the","count":1},{"next":"house and frank","previous":"choose between the","count":1},{"next":"house are no","previous":"beds in the","count":1},{"next":"to see the","previous":"graham and will","count":1}]},{"secret_word":"bohemia","clues":[{"next":"a man of","previous":"a prince of","count":17},{"next":"letters of two","previous":"a prince of","count":12},{"next":"hungary and lombardy","previous":"the king of","count":1},{"next":"which is the","previous":"the odor of","count":1},{"next":"was an utterly","previous":"for whom this","count":1},{"next":"and o how","previous":"a peep into","count":1},{"next":"and a great","previous":"he was from","count":1},{"next":"and seen prague","previous":"had travelled into","count":1},{"next":"who married and","previous":"bridegroom of parisian","count":1},{"next":"and poisoning my","previous":"slang of parisian","count":1},{"next":"protestantism was stifled","previous":"austria bavaria and","count":1},{"next":"their mother country","previous":"tribes who call","count":1},{"next":"bolingbroke bonn boston","previous":"bismarck blackwood boehm","count":1}]},{"secret_word":"boleslas","clues":[{"next":"had scarcely touched","previous":"to the adventure","count":3},{"next":"gorka how would","previous":"her mother and","count":3},{"next":"to forget his","previous":"so striking caused","count":3},{"next":"taking her hand","previous":"my word replied","count":3},{"next":"and that will","previous":"promise too said","count":3},{"next":"with the bitterest","previous":"happy couple tortured","count":3},{"next":"would have been","previous":"left and undoubtedly","count":3},{"next":"marinski graboski i","previous":"something to drink","count":3},{"next":"distinguished an intention","previous":"eagerness in which","count":3},{"next":"was so proud","previous":"energy of which","count":3},{"next":"suffered one of","previous":"connected with him","count":3},{"next":"gorka's madness which","previous":"the story of","count":2}]},{"secret_word":"bonzes","clues":[{"next":"of the temple","previous":"of the head","count":4},{"next":"and above all","previous":"up by the","count":4},{"next":"through this long","previous":"while following the","count":4},{"next":"officiate to the","previous":"temple where the","count":4},{"next":"sit immovable embodiments","previous":"open temple the","count":4},{"next":"which is situated","previous":"our friends the","count":4},{"next":"notwithstanding an unctuousness","previous":"our friends the","count":4},{"next":"in yellow robes","previous":"only associates were","count":1},{"next":"who hide their","previous":"to the vilest","count":1},{"next":"talapoins and such","previous":"manner of buddhists","count":1},{"next":"talapoins and suchlike","previous":"manner of buddists","count":1},{"next":"too just joking","previous":"that's it and","count":1}]},{"secret_word":"bookmarks","clues":[{"next":"or pointers at","previous":"short list of","count":57},{"next":"is an attested","previous":"by way of","count":1},{"next":"from the entire","previous":"lair etext editor's","count":1},{"next":"from the complete","previous":"lair etext editor's","count":1},{"next":"a heart break","previous":"etext editor s","count":1}]},{"secret_word":"brigard","clues":[{"next":"that everything that","previous":"and respect for","count":3},{"next":"whose principles forbade","previous":"the count de","count":3},{"next":"who came to","previous":"he wished for","count":3},{"next":"said for i","previous":"to meet you","count":3},{"next":"turned to crozat","previous":"were both gone","count":3},{"next":"the same man","previous":"appearance of old","count":3},{"next":"who received him","previous":"shook hands with","count":3},{"next":"take seriously an","previous":"pained to see","count":3},{"next":"and saniel was","previous":"all gone but","count":2},{"next":"and saniel's old","previous":"men who accompanied","count":2},{"next":"concluded the discussion","previous":"at the end","count":2},{"next":"and advised saniel","previous":"crozat concurred with","count":2}]},{"secret_word":"buxieres","clues":[{"next":"thought she would","previous":"a moment de","count":3},{"next":"threw his arms","previous":"when julien de","count":3},{"next":"provoked at the","previous":"it insisted de","count":3},{"next":"i was just","previous":"you monsieur de","count":3},{"next":"observed with pain","previous":"alone julien de","count":3},{"next":"send for the","previous":"night monsieur de","count":3},{"next":"matters might in","previous":"perhaps monsieur de","count":3},{"next":"first of all","previous":"reasons monsieur de","count":3},{"next":"that reine wished","previous":"message to de","count":3},{"next":"do you know","previous":"resumed monsieur de","count":3},{"next":"walked beside reine","previous":"tacit permission de","count":3}]},{"secret_word":"caffie","clues":[{"next":"is pronounced madame","previous":"the name of","count":3},{"next":"he had not","previous":"the death of","count":3},{"next":"raised the lamp","previous":"the moment when","count":3},{"next":"and florentin and","previous":"the affair of","count":3},{"next":"exasperated her she","previous":"the assassination of","count":3},{"next":"and in the","previous":"to him of","count":3},{"next":"who until then","previous":"not curious that","count":3},{"next":"lying in his","previous":"if he saw","count":3},{"next":"and taking enough","previous":"idea of strangling","count":3},{"next":"by sending them","previous":"bills taken from","count":3},{"next":"was assassinated at","previous":"five o'clock that","count":2},{"next":"and balzajette's explanations","previous":"her questions regarding","count":2}]},{"secret_word":"camier","clues":[{"next":"whose ruddy face","previous":"was monsieur de","count":3},{"next":"drove with the","previous":"which monsieur de","count":3},{"next":"with the sagacity","previous":"said monsieur de","count":3},{"next":"whose caps flashed","previous":"from monsieur de","count":3},{"next":"attributed it to","previous":"like monsieur de","count":3},{"next":"said the baron","previous":"you remain here","count":3},{"next":"as he parted","previous":"exclaimed monsieur de","count":3},{"next":"suddenly as he","previous":"exclaimed monsieur de","count":3},{"next":"who has but","previous":"scandalized monsieur de","count":3},{"next":"who were cognisant","previous":"and madame r","count":1},{"next":"on the lacy","previous":"of a r","count":1},{"next":"and the duc","previous":"friends madame r","count":1}]},{"secret_word":"camors","clues":[{"next":"slightly moist rolling","previous":"the eyes of","count":3},{"next":"turned on the","previous":"the head of","count":3},{"next":"did not admit","previous":"the health of","count":3},{"next":"loudly raised then","previous":"the voice of","count":3},{"next":"yielding to considerations","previous":"the comtesse de","count":3},{"next":"refused hesitated made","previous":"men love them","count":3},{"next":"and renee mauperin","previous":"were madame de","count":3},{"next":"did not descend","previous":"end of september","count":3},{"next":"white with foam","previous":"favorite mare of","count":3},{"next":"by octave feuillet","previous":"widger monsieur de","count":2},{"next":"refused hesitated made","previous":"but in battalions","count":1}]},{"secret_word":"campvallon","clues":[{"next":"was strolling beside","previous":"the marquise de","count":3},{"next":"against the life","previous":"of madame de","count":3},{"next":"who soon came","previous":"for madame de","count":3},{"next":"and he attributed","previous":"to madame de","count":3},{"next":"the sweetest period","previous":"to madame de","count":3},{"next":"the goal of","previous":"to madame de","count":3},{"next":"on entering the","previous":"after madame de","count":3},{"next":"had herself furnished","previous":"provoke madame de","count":3},{"next":"experienced a serious","previous":"winter madame de","count":3},{"next":"which could be","previous":"twelve leagues from","count":3},{"next":"heard some one","previous":"o'clock madame de","count":2}]},{"secret_word":"canadian","clues":[{"next":"institute for historical","previous":"available by the","count":19},{"next":"enterprise thinks that","previous":"the russian and","count":1},{"next":"artist who occupied","previous":"name of the","count":1},{"next":"mica mining company","previous":"was headed 'the","count":1},{"next":"mica mine on","previous":"saw the name","count":1},{"next":"mica mine and","previous":"will call the","count":1},{"next":"mining company he","previous":"regard to the","count":1},{"next":"magnates who happened","previous":"got from some","count":1},{"next":"opening that might","previous":"notion of a","count":1},{"next":"mica mining company","previous":"referring to the","count":1},{"next":"horse that was","previous":"natty little french","count":1},{"next":"express pulled by","previous":"junction when the","count":1}]},{"secret_word":"castagna","clues":[{"next":"with his long","previous":"of the palais","count":3},{"next":"that he had","previous":"of the palais","count":3},{"next":"that historical garden","previous":"of the palais","count":3},{"next":"was to realize","previous":"at the palais","count":3},{"next":"she had been","previous":"to the palais","count":3},{"next":"family in its","previous":"came upon the","count":3},{"next":"playing on their","previous":"said to cardinal","count":3},{"next":"where they are","previous":"from the palais","count":3},{"next":"to a joint","previous":"just sold palais","count":3},{"next":"with her hafner","previous":"visited the palais","count":3},{"next":"apartments and they","previous":"magnificence of the","count":3},{"next":"paolo uccello and","previous":"pollajuoli andrea del","count":3}]},{"secret_word":"cayrol","clues":[{"next":"despite jeanne who","previous":"and advanced toward","count":3},{"next":"in a travelling","previous":"the same moment","count":3},{"next":"had done it","previous":"the idea that","count":3},{"next":"from the outside","previous":"the voice of","count":3},{"next":"falling into an","previous":"most miserable sobbed","count":3},{"next":"they went down","previous":"had received from","count":3},{"next":"serge thought he","previous":"had gone to","count":3},{"next":"a heavy step","previous":"had indeed evoked","count":3},{"next":"to prevent his","previous":"one word to","count":3},{"next":"when he comes","previous":"i say to","count":3},{"next":"entering his wife's","previous":"fancy she saw","count":2}]},{"secret_word":"center","clues":[{"next":"of the room","previous":"stood in the","count":20},{"next":"of the room","previous":"table in the","count":17},{"next":"aisle and look","previous":"in the house","count":1},{"next":"of festivities that","previous":"he was the","count":1},{"next":"of the vance","previous":"to be the","count":1},{"next":"of the room","previous":"enter from the","count":1},{"next":"any better'n he","previous":"have hit exact","count":1},{"next":"and a piano","previous":"table in the","count":1},{"next":"about which for","previous":"locust was the","count":1},{"next":"of the floor","previous":"upward from the","count":1},{"next":"of his forehead","previous":"veins in the","count":1},{"next":"of which a","previous":"desks in the","count":1},{"next":"of the flickering","previous":"leader in the","count":1},{"next":"bespeaking a new","previous":"balls in each","count":1}]},{"secret_word":"cercle","clues":[{"next":"has just had","previous":"of the grand","count":3},{"next":"gave serge a","previous":"to the grand","count":3},{"next":"where we go","previous":"we have the","count":3},{"next":"at the hour","previous":"voice at the","count":3},{"next":"with their glaring","previous":"club the grand","count":3},{"next":"which is not","previous":"shooting and the","count":3},{"next":"de la chasse","previous":"note to the","count":3},{"next":"de la chasse","previous":"hastened to the","count":3},{"next":"de la rue","previous":"altercation at the","count":3},{"next":"d or n","previous":"v nus aucun","count":1},{"next":"blanch tre autour","previous":"et porte un","count":1},{"next":"de famille applaudit","previous":"l'enfant parait le","count":1},{"next":"militaire in paris","previous":"vasselot at the","count":1}]},{"secret_word":"cernay","clues":[{"next":"became unsettled and","previous":"the weather at","count":3},{"next":"is a vast","previous":"the chateau of","count":3},{"next":"where the marriage","previous":"to morrow for","count":3},{"next":"gallop there to","previous":"made mademoiselle de","count":3},{"next":"that terrible night","previous":"had conceived at","count":3},{"next":"not as in","previous":"settled themselves at","count":3},{"next":"simply tendering him","previous":"said mademoiselle de","count":3},{"next":"was really happy","previous":"sovereign lord of","count":3},{"next":"seizing the hands","previous":"cried mademoiselle de","count":3},{"next":"clinging to him","previous":"cried mademoiselle de","count":3},{"next":"she was surprised","previous":"desvarennes arrived at","count":3}]},{"secret_word":"chapron","clues":[{"next":"fixed upon maitland","previous":"the eyes of","count":3},{"next":"with all the","previous":"time of aretin","count":3},{"next":"might have been","previous":"between gorka and","count":3},{"next":"of the two","previous":"certainly informed by","count":3},{"next":"apologize for his","previous":"words and monsieur","count":3},{"next":"stirred within her","previous":"blood of colonel","count":3},{"next":"prevented you from","previous":"those of florent","count":3},{"next":"and she quarrels","previous":"husband and florent","count":3},{"next":"than to arrange","previous":"render our brave","count":3},{"next":"always faithful was","previous":"bed while florent","count":3},{"next":"should not be","previous":"gorka to monsieur","count":3}]},{"secret_word":"chapter","clues":[{"next":"chapter chapter chapter","previous":"chapter chapter chapter","count":153},{"next":"covers for fourteen","previous":"of the preceding","count":1},{"next":"could have precisely","previous":"in the preceding","count":1},{"next":"his interpreter did","previous":"to write this","count":1},{"next":"ii metz with","previous":"part ii lorraine","count":1},{"next":"with these words","previous":"history begins this","count":1},{"next":"to an end","previous":"brought this short","count":1},{"next":"giving the adventures","previous":"coming to the","count":1},{"next":"of the second","previous":"us read another","count":1},{"next":"xii precy sur","previous":"forests of chantilly","count":1},{"next":"xvii the stuffed","previous":"spring in charleville","count":1},{"next":"i the traveller","previous":"hut at bar","count":1}]},{"secret_word":"charnot","clues":[{"next":"i think we","previous":"by saying monsieur","count":3},{"next":"how sorry i","previous":"to tell monsieur","count":3},{"next":"will never change","previous":"that mademoiselle jeanne","count":3},{"next":"said he i","previous":"my dear monsieur","count":3},{"next":"of the institute","previous":"i am monsieur","count":3},{"next":"bringing his pretty","previous":"ordinary to mademoiselle","count":3},{"next":"is aware of","previous":"confess that mademoiselle","count":3},{"next":"can go and","previous":"room where monsieur","count":3},{"next":"can you guess","previous":"talk my dear","count":3},{"next":"upset by the","previous":"add that mademoiselle","count":3},{"next":"have left paris","previous":"monsieur and mademoiselle","count":3},{"next":"i'm convinced of","previous":"dowry he's after","count":2}]},{"secret_word":"chebe","clues":[{"next":"appeared little monsieur","previous":"him and monsieur","count":3},{"next":"and delobelle his","previous":"two faithful borrowers","count":3},{"next":"and desiree delobelle","previous":"days of little","count":3},{"next":"the anger of","previous":"against his little","count":3},{"next":"a grudge because","previous":"they bear little","count":3},{"next":"sobbing in the","previous":"could hear madame","count":3},{"next":"i am selling","previous":"not moving monsieur","count":3},{"next":"flushed and breathless","previous":"appeared little monsieur","count":3},{"next":"sidonie risler had","previous":"dreams of little","count":3},{"next":"in his long","previous":"moments earlier monsieur","count":3},{"next":"of the old","previous":"girl the little","count":3},{"next":"was fully convinced","previous":"eloquent that monsieur","count":3}]},{"secret_word":"chorche","clues":[{"next":"is this true","previous":"this true madame","count":3},{"next":"would pass her","previous":"his dear madame","count":3},{"next":"bending over some","previous":"his dear madame","count":3},{"next":"risler advised her","previous":"his dear madame","count":3},{"next":"the wife of","previous":"he called madame","count":3},{"next":"you could not","previous":"but you madame","count":3},{"next":"was always there","previous":"thought of madame","count":3},{"next":"who was drawing","previous":"master of monsieur","count":3},{"next":"muttered poor sigismond","previous":"monsieur chorche monsieur","count":3},{"next":"the only two","previous":"frantz and madame","count":3},{"next":"walking in front","previous":"risler and madame","count":3}]},{"secret_word":"choulette","clues":[{"next":"is right too","previous":"and that brute","count":3},{"next":"lighting his pipe","previous":"in a box","count":3},{"next":"appeared with the","previous":"at table when","count":3},{"next":"if i were","previous":"be mine monsieur","count":3},{"next":"which he understood","previous":"ardent praises of","count":3},{"next":"may come without","previous":"possible too that","count":3},{"next":"is not a","previous":"insist that monsieur","count":3},{"next":"the flame of","previous":"bald cranium of","count":3},{"next":"has written me","previous":"martin darling monsieur","count":3},{"next":"for all our","previous":"marmet for monsieur","count":3}]},{"secret_word":"chrysantheme","clues":[{"next":"always eagerly attentive","previous":"the white mats","count":3},{"next":"has left them","previous":"the summer blooms","count":3},{"next":"oyouki and i","previous":"the town yves","count":3},{"next":"what will they","previous":"of yves and","count":3},{"next":"lights a lantern","previous":"for yves san","count":3},{"next":"yves is in","previous":"with regard to","count":3},{"next":"it is indeed","previous":"to yves about","count":3},{"next":"which though translating","previous":"her better than","count":3},{"next":"i listen with","previous":"between yves and","count":3},{"next":"was very charming","previous":"sweet and little","count":3},{"next":"madame prune her","previous":"helping hand yves","count":3},{"next":"with her japanese","previous":"vases arranged by","count":3}]},{"secret_word":"cibo","clues":[{"next":"the doctor declared","previous":"the care of","count":3},{"next":"who had brought","previous":"for us concluded","count":3},{"next":"answered for the","previous":"a stroll but","count":3},{"next":"pietrapertosa hafner ardea","previous":"in vain did","count":3},{"next":"and pietrapertosa who","previous":"he continued addressing","count":3},{"next":"with an eagerness","previous":"that time replied","count":3},{"next":"as a paddock","previous":"had formerly served","count":3},{"next":"i will guarantee","previous":"is well began","count":3},{"next":"had ceased since","previous":"if pietrapertosa and","count":3},{"next":"and pietrapertosa such","previous":"those of montfanon","count":3},{"next":"and of pietrapertosa","previous":"determine that of","count":3}]},{"secret_word":"cicalas","clues":[{"next":"accompanies them in","previous":"of crickets and","count":4},{"next":"are mute odors","previous":"old roof the","count":4},{"next":"that seems to","previous":"song of the","count":4},{"next":"ceaseless strident and","previous":"song of the","count":4},{"next":"on the roof","previous":"hour while the","count":4},{"next":"which filled the","previous":"sound of the","count":4},{"next":"make themselves heard","previous":"cocks and the","count":4},{"next":"continue their sonorous","previous":"the distance the","count":3},{"next":"around us keep","previous":"to say the","count":3},{"next":"i mount to","previous":"noise of the","count":3},{"next":"then be mute","previous":"and halcyons and","count":1},{"next":"was pleasant to","previous":"cry of the","count":1}]},{"secret_word":"claudet","clues":[{"next":"had undertaken for","previous":"the district which","count":3},{"next":"the ancient minister","previous":"of medicine and","count":3},{"next":"stoops to pick","previous":"at this moment","count":3},{"next":"and secondly to","previous":"to hear about","count":3},{"next":"his share in","previous":"not help envying","count":3},{"next":"who would at","previous":"have driven away","count":3},{"next":"had infused into","previous":"much living heat","count":3},{"next":"was cured opportunely","previous":"marriage the minister","count":3},{"next":"is on duty","previous":"approach of night","count":3},{"next":"since she is","previous":"must have loved","count":3},{"next":"is dead and","previous":"particularly oracular air","count":3},{"next":"she could not","previous":"afterthought in renouncing","count":3},{"next":"sejournant volunteer in","previous":"decease of germain","count":3}]},{"secret_word":"clifton","clues":[{"next":"london grosvenor street","previous":"ives to louisa","count":22},{"next":"of whom his","previous":"he would silence","count":1},{"next":"and i now","previous":"only of coke","count":1},{"next":"hill for the","previous":"were sent to","count":1},{"next":"to be a","previous":"now know coke","count":1},{"next":"be not there","previous":"direction 'if miss","count":1},{"next":"as to a","previous":"added by louisa","count":1},{"next":"to guy fairfax","previous":"letter cxxvii coke","count":1},{"next":"to guy fairfax","previous":"letter cxxv coke","count":1},{"next":"to guy fairfax","previous":"letter cxxix coke","count":1},{"next":"of consumption before","previous":"privation died at","count":1},{"next":"oh my friend","previous":"ives to louisa","count":1}]},{"secret_word":"contessina","clues":[{"next":"in her pretty","previous":"she called the","count":3},{"next":"busy at that","previous":"visit to the","count":3},{"next":"replied dorsenne if","previous":"you are here","count":3},{"next":"said he the","previous":"you are right","count":3},{"next":"said he when","previous":"you come opportunely","count":3},{"next":"still doubted and","previous":"signs that the","count":3},{"next":"with a glance","previous":"again toward the","count":3},{"next":"and you are","previous":"again vexed you","count":3},{"next":"he was singularly","previous":"mission to the","count":3},{"next":"was the victim","previous":"maud's husband the","count":2},{"next":"burst out laughing","previous":"chair and the","count":1},{"next":"emilia viviani who","previous":"noble lady the","count":1}]},{"secret_word":"context","clues":[{"next":"of any of","previous":"read the entire","count":17},{"next":"of the quotations","previous":"location and complete","count":5},{"next":"with a concentration","previous":"and assimilated their","count":1},{"next":"glowing with a","previous":"all the noble","count":1},{"next":"das man vom","previous":"ever had a","count":1},{"next":"i have no","previous":"occurred in the","count":1},{"next":"in society and","previous":"things from his","count":1},{"next":"suggests that he","previous":"did but the","count":1},{"next":"but full for","previous":"torn from their","count":1},{"next":"if they had","previous":"broken from their","count":1},{"next":"with a melancholy","previous":"expression in another","count":1},{"next":"with a given","previous":"social and political","count":1}]},{"secret_word":"coppee","clues":[{"next":"with a preface","previous":"youth by francois","count":3},{"next":"he woke up","previous":"the reputation of","count":3},{"next":"can be seen","previous":"of an artist","count":3},{"next":"francois edouard joachim","previous":"french academy francois","count":3},{"next":"is parisian by","previous":"to enjoy for","count":3},{"next":"sticks rigorously to","previous":"which is tedious","count":3},{"next":"belongs to the","previous":"we contemplate him","count":3},{"next":"most fully possesses","previous":"will deny that","count":3},{"next":"became as before","previous":"juvenile sarah bernhardt","count":3},{"next":"was born in","previous":"francois edouard joachim","count":3},{"next":"break in his","previous":"youth by francois","count":1},{"next":"but by the","previous":"contes by francois","count":1}]},{"secret_word":"corandeuil","clues":[{"next":"stretched out in","previous":"was mademoiselle de","count":3},{"next":"asked me for","previous":"which mademoiselle de","count":3},{"next":"as she laid","previous":"said mademoiselle de","count":3},{"next":"tried to raise","previous":"while mademoiselle de","count":3},{"next":"aroused from her","previous":"she mademoiselle de","count":3},{"next":"noticing for the","previous":"asked mademoiselle de","count":3},{"next":"a second time","previous":"exclaimed mademoiselle de","count":3},{"next":"in a falsetto","previous":"exclaimed mademoiselle de","count":3},{"next":"who thought that","previous":"exclaimed mademoiselle de","count":3},{"next":"into a second","previous":"metamorphosing mademoiselle de","count":3}]},{"secret_word":"cormier","clues":[{"next":"and nougarede and","previous":"of phillis madame","count":3},{"next":"against whom so","previous":"was not florentin","count":3},{"next":"fell into a","previous":"in prison madame","count":3},{"next":"opened the door","previous":"his ring madame","count":3},{"next":"said with emotion","previous":"her own madame","count":3},{"next":"spoke of it","previous":"than once madame","count":3},{"next":"and phillis would","previous":"emotion of madame","count":3},{"next":"was in her","previous":"proved that madame","count":3},{"next":"in whom at","previous":"do for madame","count":3},{"next":"interrupted by going","previous":"silences that madame","count":3},{"next":"with more decision","previous":"reproach said madame","count":3}]},{"secret_word":"corners","clues":[{"next":"of her eyes","previous":"out of the","count":28},{"next":"of the rug","previous":"and catching the","count":1},{"next":"east of the","previous":"of those fine","count":1},{"next":"of the earth","previous":"for the four","count":1},{"next":"of which were","previous":"with writing the","count":1},{"next":"with my notions","previous":"life squares nay","count":1},{"next":"of the pack","previous":"under the four","count":1},{"next":"searching the faces","previous":"shadows in the","count":1},{"next":"of the market","previous":"either at the","count":1},{"next":"and pits of","previous":"flashing it into","count":1},{"next":"the rash couples","previous":"got tangled in","count":1},{"next":"of the mouth","previous":"extended below the","count":1},{"next":"of the earth","previous":"errant explore the","count":1}]},{"secret_word":"courtesan","clues":[{"next":"s life the","previous":"scenes from a","count":42},{"next":"s life a","previous":"scenes from a","count":11},{"next":"s life another","previous":"scenes from a","count":10},{"next":"s life honorine","previous":"scenes from a","count":9},{"next":"s life letters","previous":"scenes from a","count":8},{"next":"s life ursule","previous":"scenes from a","count":4},{"next":"she could be","previous":"the most fascinating","count":2},{"next":"opening one of","previous":"woman said the","count":2},{"next":"who discovered cataline's","previous":"it was a","count":2},{"next":"s life berthier","previous":"scenes from a","count":2},{"next":"and had succeeded","previous":"of a petty","count":1},{"next":"cursing mercenary love","previous":"as the unhappy","count":1},{"next":"invited by titian","previous":"as the handsomest","count":1},{"next":"than a queen","previous":"more like a","count":1},{"next":"ladies did not","previous":"against all the","count":1},{"next":"after paying the","previous":"would of some","count":1}]},{"secret_word":"courtesan's","clues":[{"next":"life a daughter","previous":"scenes from a","count":5},{"next":"life the firm","previous":"scenes from a","count":4},{"next":"life another study","previous":"scenes from a","count":4},{"next":"life honorine the","previous":"scenes from a","count":4},{"next":"life the country","previous":"scenes from a","count":3},{"next":"life beatrix the","previous":"scenes from a","count":3},{"next":"temperament that prevented","previous":"her inability her","count":2},{"next":"life the government","previous":"scenes from a","count":2},{"next":"life cousin pons","previous":"scenes from a","count":2},{"next":"life letters of","previous":"scenes from a","count":2},{"next":"life nathan madame","previous":"scenes from a","count":1},{"next":"life ursule mirouet","previous":"scenes from a","count":1},{"next":"life tillet ferdinand","previous":"scenes from a","count":1},{"next":"life modeste mignon","previous":"scenes from a","count":1}]},{"secret_word":"coverley","clues":[{"next":"he was in","previous":"sir humphrey de","count":7},{"next":"was the tamest","previous":"sir roger de","count":6},{"next":"and sir andrew","previous":"sir roger de","count":5},{"next":"to pass away","previous":"sir roger de","count":5},{"next":"applied to a","previous":"of roger of","count":2},{"next":"a whimsical country","previous":"sir roger de","count":2},{"next":"is said to","previous":"sir roger de","count":2},{"next":"papers was twice","previous":"sir roger de","count":2},{"next":"'against evil speaking","previous":"sir roger de","count":2},{"next":"and his christmas","previous":"sir roger de","count":1},{"next":"was known commenced","previous":"sir roger de","count":1},{"next":"because it happened","previous":"sir roger de","count":1},{"next":"papers becomes positively","previous":"sir roger de","count":1}]},{"secret_word":"cymier","clues":[{"next":"on a low","previous":"and gerard de","count":3},{"next":"secretary of embassy","previous":"the vicomte de","count":3},{"next":"seems to have","previous":"of monsieur de","count":3},{"next":"or like marien","previous":"all were like","count":3},{"next":"whom possibly you","previous":"a monsieur de","count":3},{"next":"or even talbrun","previous":"with wermant or","count":3},{"next":"was discouraged by","previous":"that gerard de","count":3},{"next":"whom she loves","previous":"not monsieur de","count":3},{"next":"behave in these","previous":"would gerard de","count":3},{"next":"has written a","previous":"angrily monsieur de","count":3}]},{"secret_word":"dammauville","clues":[{"next":"motionless and pink","previous":"his chair madame","count":3},{"next":"say to her","previous":"he heard madame","count":3},{"next":"might have told","previous":"he dreaded madame","count":3},{"next":"when the night","previous":"to see madame","count":3},{"next":"did after the","previous":"her what madame","count":3},{"next":"had said nothing","previous":"proved that madame","count":3},{"next":"he was so","previous":"death of madame","count":3},{"next":"pulled the bellcord","previous":"same time madame","count":3},{"next":"caffie and florentin","previous":"dwelt on madame","count":3},{"next":"nougarede had summoned","previous":"default of madame","count":3},{"next":"the only hope","previous":"intervention of madame","count":3},{"next":"in the night","previous":"resuscitated by madame","count":3}]},{"secret_word":"dechartre","clues":[{"next":"had modelled the","previous":"a medallion wherein","count":3},{"next":"came into the","previous":"at this instant","count":3},{"next":"and miss bell","previous":"her box only","count":3},{"next":"who designed this","previous":"it is monsieur","count":3},{"next":"and paul vence","previous":"out when jacques","count":3},{"next":"through the door","previous":"soul had followed","count":3},{"next":"who was looking","previous":"she said to","count":3},{"next":"i hope you","previous":"she turned toward","count":3},{"next":"is full of","previous":"mind of monsieur","count":3},{"next":"my friend do","previous":"pointed toward neuilly","count":3},{"next":"with his hand","previous":"cloak she saw","count":3},{"next":"of the girl","previous":"profile sketch by","count":3}]},{"secret_word":"delobelle","clues":[{"next":"in his stovepipe","previous":"and the illustrious","count":3},{"next":"at a cafe","previous":"of the illustrious","count":3},{"next":"appeared to his","previous":"picture the illustrious","count":3},{"next":"summoned all her","previous":"was flying desire","count":3},{"next":"obstinately declined to","previous":"but the woman","count":3},{"next":"and lectured her","previous":"at the woman","count":3},{"next":"had been making","previous":"time past mamma","count":3},{"next":"her old delobelle","previous":"she thought of","count":3},{"next":"who was asleep","previous":"because of madame","count":3},{"next":"his first moment","previous":"borrowers chebe and","count":3},{"next":"it's the noblest","previous":"may say continued","count":2}]},{"secret_word":"desiree","clues":[{"next":"opens the wardrobe","previous":"by very softly","count":3},{"next":"and strengthened her","previous":"was made angered","count":3},{"next":"noticed the striking","previous":"in her life","count":3},{"next":"began at once","previous":"who had brought","count":3},{"next":"saw anew all","previous":"her eyes closed","count":3},{"next":"who came toiling","previous":"it was really","count":3},{"next":"sat up in","previous":"from her torpor","count":3},{"next":"bids adieu to","previous":"feeling and poor","count":3},{"next":"like the dainty","previous":"words were to","count":3},{"next":"timidly i think","previous":"do well pursued","count":3},{"next":"felt a terrible","previous":"few short hours","count":3},{"next":"whose ears i","previous":"think i want","count":1}]},{"secret_word":"desvanneaux","clues":[{"next":"not being in","previous":"and the comtesse","count":3},{"next":"it is that","previous":"are wrong monsieur","count":3},{"next":"tried to efface","previous":"of which madame","count":3},{"next":"will be sure","previous":"day appointed monsieur","count":3},{"next":"would be pitiless","previous":"here and madame","count":3},{"next":"shall have nothing","previous":"desire that monsieur","count":3},{"next":"it mattered little","previous":"curious as the","count":3},{"next":"who was invited","previous":"displeasure of madame","count":3},{"next":"takes possession of","previous":"asylum before monsieur","count":3},{"next":"in her usual","previous":"inauguration said madame","count":3},{"next":"thinks that this","previous":"poquelin but madame","count":3}]},{"secret_word":"desvarennes","clues":[{"next":"which had never","previous":"the house of","count":3},{"next":"going toward the","previous":"he saw madame","count":3},{"next":"and threw her","previous":"he seized madame","count":3},{"next":"does not go","previous":"law of madame","count":3},{"next":"went up to","previous":"little staircase madame","count":3},{"next":"could not oppose","previous":"known that madame","count":3},{"next":"he added to","previous":"turning toward madame","count":3},{"next":"to apprise her","previous":"back to madame","count":3},{"next":"gravely and you","previous":"matters said madame","count":3},{"next":"before seeing micheline","previous":"dreaded meeting madame","count":3},{"next":"was about to","previous":"resounded as madame","count":3}]},{"secret_word":"diou","clues":[{"next":"djen dji and","previous":"the direction of","count":4},{"next":"djen dji which","previous":"the road to","count":4},{"next":"djen dji to","previous":"the footpaths of","count":4},{"next":"djen dji all","previous":"we return to","count":4},{"next":"djen dji in","previous":"we arrive at","count":4},{"next":"djen dji hills","previous":"foot of the","count":4},{"next":"djen dji to","previous":"going up to","count":4},{"next":"djen dji to","previous":"straight up to","count":4},{"next":"djen dji they","previous":"blossoms brought from","count":3}]},{"secret_word":"distributed","clues":[{"next":"proofreading team at","previous":"and the online","count":344},{"next":"proofreading team the","previous":"and the online","count":26},{"next":"and becomes lighter","previous":"impartially evil is","count":2},{"next":"proofreaders the babylonian","previous":"by the pg","count":1},{"next":"proofreaders black jack","previous":"and project gutenberg","count":1},{"next":"them in comfort","previous":"living room and","count":1},{"next":"those wholesale invitations","previous":"you only hadn't","count":1},{"next":"among all the","previous":"understanding that were","count":1},{"next":"us all in","previous":"us away and","count":1},{"next":"proofreading team bertha","previous":"project gutenberg online","count":1},{"next":"proofreading team viviette","previous":"project gutenberg online","count":1},{"next":"by mysterious discrepancies","previous":"array of partners","count":1},{"next":"proofreaders illustration the","previous":"alberto and pg","count":1}]},{"secret_word":"djen","clues":[{"next":"dji to see","previous":"up to diou","count":4},{"next":"dji to join","previous":"up to diou","count":4},{"next":"dji we cross","previous":"up to diou","count":4},{"next":"dji all wet","previous":"return to diou","count":4},{"next":"dji they had","previous":"brought from diou","count":4},{"next":"dji and our","previous":"direction of diou","count":4},{"next":"dji which i","previous":"road to diou","count":4},{"next":"dji with a","previous":"suburb of diou","count":4},{"next":"dji in the","previous":"arrive at diou","count":4},{"next":"dji to laugh","previous":"footpaths of diou","count":4},{"next":"dji the thin","previous":"roof of diou","count":3},{"next":"dji in the","previous":"unexpectedly at diou","count":3},{"next":"anne i'll open","previous":"i get to","count":1}]},{"secret_word":"dji","clues":[{"next":"and our echoing","previous":"of diou djen","count":4},{"next":"with a person","previous":"of diou djen","count":4},{"next":"to laugh at","previous":"of diou djen","count":4},{"next":"in the midst","previous":"at diou djen","count":4},{"next":"in the starry","previous":"at diou djen","count":4},{"next":"all wet through","previous":"to diou djen","count":4},{"next":"which i shall","previous":"to diou djen","count":4},{"next":"we cross yves","previous":"to diou djen","count":4},{"next":"they had lasted","previous":"from diou djen","count":4},{"next":"the thin old","previous":"of diou djen","count":3},{"next":"to see chrysantheme","previous":"to diou djen","count":3},{"next":"to join chrysantheme","previous":"to diou djen","count":3},{"next":"to see chrysanth","previous":"to diou djen","count":1},{"next":"to join chrysanth","previous":"to diou djen","count":1}]},{"secret_word":"djin","clues":[{"next":"richisans are the","previous":"the djins or","count":4},{"next":"and i at","previous":"of a speedy","count":4},{"next":"with the umbrella","previous":"at haphazard the","count":4},{"next":"stand and engage","previous":"down to the","count":4},{"next":"and to my","previous":"fate to my","count":4},{"next":"it is up","previous":"yes replied the","count":4},{"next":"with many smiles","previous":"stops and my","count":4},{"next":"who is waiting","previous":"rice to my","count":4},{"next":"and i one","previous":"we made the","count":3},{"next":"and myself one","previous":"been making the","count":1}]},{"secret_word":"djins","clues":[{"next":"with our little","previous":"and leaving our","count":4},{"next":"or djin richisans","previous":"to land the","count":4},{"next":"who were touting","previous":"were only the","count":4},{"next":"pass by dragging","previous":"long lines of","count":4},{"next":"and five cars","previous":"we hire five","count":4},{"next":"in search of","previous":"four quick footed","count":4},{"next":"get quite bewildered","previous":"till our breathless","count":4},{"next":"hurry along and","previous":"street where vociferating","count":4},{"next":"dragged us at","previous":"three swift footed","count":3},{"next":"carts hired at","previous":"up in the","count":1},{"next":"cars are stationed","previous":"long rows of","count":1},{"next":"dragged us at","previous":"three quick footed","count":1}]},{"secret_word":"dominique","clues":[{"next":"and by mistake","previous":"the rue saint","count":3},{"next":"and the rue","previous":"the rue saint","count":3},{"next":"and on arriving","previous":"the rue saint","count":3},{"next":"the marriage preparations","previous":"the rue saint","count":3},{"next":"a few minutes","previous":"the rue saint","count":3},{"next":"was filled with","previous":"the rue saint","count":3},{"next":"he found madame","previous":"the rue saint","count":3},{"next":"with marechal who","previous":"the rue saint","count":3},{"next":"came to her","previous":"the rue saint","count":3},{"next":"is certainly one","previous":"the rue saint","count":3},{"next":"remained silent and","previous":"the rue saint","count":3},{"next":"hastened away to","previous":"the rue saint","count":3},{"next":"bouhours a learned","previous":"footnote is footnote","count":2}]},{"secret_word":"dorsenne","clues":[{"next":"vainly tried to","previous":"the entire day","count":3},{"next":"alert and foppish","previous":"of contrast of","count":3},{"next":"turning again toward","previous":"a trot and","count":3},{"next":"in that corner","previous":"was conversing with","count":3},{"next":"would not have","previous":"at that moment","count":3},{"next":"who began to","previous":"little countess replied","count":3},{"next":"who was praising","previous":"she said to","count":3},{"next":"but you are","previous":"you say replied","count":3},{"next":"if to steal","previous":"here contessina replied","count":3},{"next":"whence such reasoning","previous":"poor friend interrupted","count":3},{"next":"to rise chiding","previous":"deliberating then forced","count":3},{"next":"that is beautiful","previous":"martyrii fidem' repeated","count":2}]},{"secret_word":"dunlap","clues":[{"next":"west th st","previous":"copyrighted fiction grosset","count":23},{"next":"publishers copyright by","previous":"new york grosset","count":20},{"next":"publishers new york","previous":"copyrighted fiction grosset","count":15},{"next":"standing in the","previous":"her of cornelia","count":1},{"next":"with a whimsical","previous":"wrote to cornelia","count":1},{"next":"go and get","previous":"little baths cornelia","count":1},{"next":"had flitted together","previous":"she and cornelia","count":1},{"next":"about going on","previous":"word to cornelia","count":1},{"next":"and neatly folded","previous":"letter to cornelia","count":1},{"next":"miss theodosia wrote","previous":"letter to cornelia","count":1},{"next":"was the forerunner","previous":"letter from cornelia","count":1},{"next":"in moments of","previous":"' for cornelia","count":1},{"next":"that japan had","previous":"porch telling cornelia","count":1}]},{"secret_word":"enguerrand","clues":[{"next":"who was there","previous":"the dining room","count":3},{"next":"hindered giselle from","previous":"of the expected","count":3},{"next":"who in person","previous":"secret terror lest","count":3},{"next":"as having a","previous":"little ear of","count":3},{"next":"which always made","previous":"long name of","count":3},{"next":"in a tone","previous":"like him answered","count":3},{"next":"were how pretty","previous":"like those of","count":3},{"next":"a sugar plum","previous":"future to promise","count":3},{"next":"where his mother","previous":"curls of little","count":3},{"next":"jacqueline was discovering","previous":"complicity of little","count":3},{"next":"can spare you","previous":"castanets if monsieur","count":3},{"next":"would never have","previous":"don't imagine it","count":2},{"next":"would never have","previous":"t imagine it","count":1}]},{"secret_word":"eppie","clues":[{"next":"and wife of","previous":"was sister to","count":3},{"next":"seemed lost in","previous":"he repeated for","count":3},{"next":"gin ye brak","previous":"to mysy said","count":3},{"next":"speaking with a","previous":"saw ye said","count":3},{"next":"ye can tell","previous":"'at i care","count":3},{"next":"resumed the conversation","previous":"fairly started but","count":3},{"next":"but lasses doesna","previous":"mayna be said","count":3},{"next":"as he disappeared","previous":"leein' sam'l said","count":3},{"next":"upon silas marner","previous":"the influence of","count":2},{"next":"cried so vigorously","previous":"of water and","count":2},{"next":"mclaren was getting","previous":"to see how","count":2},{"next":"whamond who was","previous":"unique case of","count":2}]},{"secret_word":"expect","clues":[{"next":"me to do","previous":"what do you","count":24},{"next":"that it should","previous":"a right to","count":1},{"next":"her to go","previous":"that i couldn't","count":1},{"next":"a woman in","previous":"just what you","count":1},{"next":"it from a","previous":"have come to","count":1},{"next":"to find the","previous":"we may confidently","count":1},{"next":"to meet a","previous":"you can only","count":1},{"next":"too much of","previous":"well you shouldn't","count":1},{"next":"to go there","previous":"those who don't","count":1},{"next":"of these chaps","previous":"what can you","count":1},{"next":"you to do","previous":"course i wouldn't","count":1},{"next":"to quit cussin'","previous":"say i don't","count":1}]},{"secret_word":"fairfax","clues":[{"next":"london dover street","previous":"clifton to guy","count":25},{"next":"to entangle my","previous":"was like a","count":1},{"next":"the handsome soldier","previous":"himself with george","count":1},{"next":"upon this earth","previous":"being as george","count":1},{"next":"glad girl of","previous":"like this beatrice","count":1},{"next":"to track her","previous":"husband or george","count":1},{"next":"knew by his","previous":"husband whom george","count":1},{"next":"discovering her retreat","previous":"terror of george","count":1},{"next":"alone in the","previous":"interview with george","count":1},{"next":"assume her dalliance","previous":"flirtation with george","count":1},{"next":"adjusting poultices how","previous":"chess with george","count":1},{"next":"nor could she","previous":"pathway of george","count":1}]},{"secret_word":"file","clues":[{"next":"which includes the","previous":"version of this","count":95},{"next":"for those who","previous":"end of the","count":57},{"next":"and hammer into","previous":"and a nail","count":1},{"next":"was my constitutional","previous":"of this infernal","count":1},{"next":"the same number","previous":"up in double","count":1},{"next":"of greatness i","previous":"mere rank and","count":1},{"next":"towards the platform","previous":"was beginning to","count":1},{"next":"one sees such","previous":"in an endless","count":1},{"next":"through the narrowing","previous":"they walked single","count":1},{"next":"for our chains","previous":"has been the","count":1},{"next":"of supervisorship by","previous":"fall into the","count":1},{"next":"of geese on","previous":"street and a","count":1}]},{"secret_word":"florent","clues":[{"next":"chapron always faithful","previous":"the bed while","count":3},{"next":"dragged himself thither","previous":"the fact that","count":3},{"next":"was fighting for","previous":"the poor child","count":3},{"next":"to the assizes","previous":"the prosecution sent","count":3},{"next":"and if the","previous":"he insulted poor","count":3},{"next":"sank upon the","previous":"fired simultaneously and","count":3},{"next":"chapron and she","previous":"her husband and","count":3},{"next":"and he ascended","previous":"they had carried","count":3},{"next":"into a room","previous":"they had borne","count":3},{"next":"chapron prevented you","previous":"or those of","count":3},{"next":"to keep the","previous":"voice turning to","count":3},{"next":"vierzon and the","previous":"from vatan saint","count":1}]},{"secret_word":"florentin","clues":[{"next":"troubled him also","previous":"the thought of","count":3},{"next":"more than that","previous":"the mother of","count":3},{"next":"would have been","previous":"the stove and","count":3},{"next":"but this was","previous":"he could for","count":3},{"next":"that you leave","previous":"it is for","count":3},{"next":"would see her","previous":"there so that","count":3},{"next":"and with his","previous":"death created for","count":3},{"next":"between the decks","previous":"cruel to see","count":3},{"next":"to twenty years","previous":"decree that condemned","count":3},{"next":"would be saved","previous":"intervention she hoped","count":3},{"next":"had embarked for","previous":"supported by nougarede's","count":2},{"next":"which is beautiful","previous":"corneille's plays le","count":1}]},{"secret_word":"franks","clues":[{"next":"and the online","previous":"juliet sutherland charles","count":33},{"next":"and the online","previous":"produced by charles","count":30},{"next":"and the online","previous":"charles aldarondo charles","count":13},{"next":"and the online","previous":"eric eldred charles","count":11},{"next":"and the online","previous":"tonya allen charles","count":4},{"next":"a sketch of","previous":"present to the","count":1},{"next":"debra storr and","previous":"produced by charles","count":1},{"next":"then i should","previous":"i could get","count":1},{"next":"this is most","previous":"lord carrington who","count":1},{"next":"his main business","previous":"grubbing among the","count":1},{"next":"have ever been","previous":"albania where few","count":1},{"next":"and the online","previous":"martin agren charles","count":1}]},{"secret_word":"fw","clues":[{"next":"fw me me","previous":"md md fw","count":8},{"next":"me me me","previous":"md fw fw","count":8},{"next":"fw fw me","previous":"md md md","count":7},{"next":"fw fw fw","previous":"md md md","count":4},{"next":"me me me","previous":"fw fw fw","count":3},{"next":"fw me me","previous":"fw fw fw","count":2},{"next":"md lazy ones","previous":"me me aden","count":1},{"next":"fw fw fw","previous":"me me fw","count":1},{"next":"fw fw me","previous":"me fw fw","count":1},{"next":"oo roves pdfr","previous":"nite richar md","count":1},{"next":"lele md me","previous":"md md ppt","count":1},{"next":"me me fw","previous":"md fw fw","count":1},{"next":"fw fw fw","previous":"fw me me","count":1}]},{"secret_word":"garain","clues":[{"next":"with wrinkled eyes","previous":"and looking at","count":3},{"next":"had accepted the","previous":"the same morning","count":3},{"next":"will be inspired","previous":"the president replied","count":3},{"next":"and garain thinking","previous":"he had flattered","count":3},{"next":"the deputy formerly","previous":"at her right","count":3},{"next":"perhaps is lacking","previous":"count martin but","count":3},{"next":"abandoned betrayed by","previous":"pleasure of seeing","count":3},{"next":"combination he imagined","previous":"part of the","count":3},{"next":"that it would","previous":"not think monsieur","count":3},{"next":"thinking him too","previous":"flattered garain and","count":3},{"next":"is easily said","previous":"homogeneous ministry exclaimed","count":3},{"next":"offered commerce and","previous":"d'eyzelles to whom","count":2}]},{"secret_word":"gardinois","clues":[{"next":"all retired shortly","previous":"the old millionaire","count":3},{"next":"did not long","previous":"of becoming madame","count":3},{"next":"had done nothing","previous":"his chateau old","count":3},{"next":"and heaven knows","previous":"that old pere","count":3},{"next":"continued to lead","previous":"young woman old","count":3},{"next":"would gladly have","previous":"their hearts old","count":3},{"next":"at last did","previous":"they needed old","count":3},{"next":"could hear when","previous":"were all monsieur","count":3},{"next":"who had laid","previous":"sometimes while grandfather","count":3},{"next":"who seized upon","previous":"agreed with old","count":3},{"next":"who sat by","previous":"pleasantries of grandfather","count":3}]},{"secret_word":"generously","clues":[{"next":"made available by","previous":"produced from images","count":78},{"next":"and piously despatched","previous":"which they so","count":2},{"next":"broad the chairs","previous":"the rooms were","count":1},{"next":"and manfully declared","previous":"to the last","count":1},{"next":"especially as you","previous":"to me so","count":1},{"next":"in this instance","previous":"will not act","count":1},{"next":"graceful lines as","previous":"same broad and","count":1},{"next":"and ma could","previous":"exclaimed her brother","count":1},{"next":"with all men","previous":"conscious of sympathising","count":1},{"next":"than ever one","previous":"treated me more","count":1},{"next":"arranged by you","previous":"separation nobly and","count":1},{"next":"inviting him with","previous":"oaks that stood","count":1}]},{"secret_word":"gerards","clues":[{"next":"but this time","previous":"name of the","count":3},{"next":"he quickly walked","previous":"his friends the","count":3},{"next":"a few visits","previous":"only paid the","count":3},{"next":"just one month","previous":"to the poor","count":3},{"next":"and amedee presented","previous":"visit to the","count":3},{"next":"all they could","previous":"visit to the","count":3},{"next":"a miserable commonplace","previous":"home of the","count":3},{"next":"sympathized politely with","previous":"times for the","count":3},{"next":"and they seated","previous":"went to the","count":3},{"next":"it is always","previous":"thing at the","count":3},{"next":"he would keep","previous":"evenings with the","count":3},{"next":"maria always asked","previous":"amedee paid the","count":3},{"next":"praised louise's goodness","previous":"humble friends the","count":2}]},{"secret_word":"gerfaut","clues":[{"next":"saw him riding","previous":"he had left","count":3},{"next":"followed his example","previous":"at a trot","count":3},{"next":"slowly as he","previous":"that murder continued","count":3},{"next":"well known by","previous":"friends monsieur de","count":3},{"next":"who was impatient","previous":"your way said","count":3},{"next":"looking at him","previous":"well monsieur said","count":3},{"next":"standing beside his","previous":"eyes and recognized","count":3},{"next":"with a half","previous":"refuse that said","count":3},{"next":"replied i too","previous":"know all that","count":3},{"next":"at this post","previous":"put our friend","count":3},{"next":"threw such a","previous":"nobody stirred but","count":3},{"next":"by charles de","previous":"by david widger","count":2}]},{"secret_word":"giselle","clues":[{"next":"took him by","previous":"the youth of","count":3},{"next":"was melted by","previous":"the heart of","count":3},{"next":"with sudden and","previous":"for you said","count":3},{"next":"how i should","previous":"all by yourself","count":3},{"next":"in her nervous","previous":"his face that","count":3},{"next":"with a little","previous":"has returned answered","count":3},{"next":"desirous that all","previous":"increasing intimacy with","count":3},{"next":"went home to","previous":"gentle conspirators before","count":3},{"next":"with passionate eagerness","previous":"sofa and approached","count":3},{"next":"read in fred's","previous":"in telling us","count":2},{"next":"wiping her friend's","previous":"than that said","count":2},{"next":"frank golding's re","previous":"do l'amourette de","count":2}]},{"secret_word":"glady","clues":[{"next":"lived in dread","previous":"of poor men","count":3},{"next":"and his visit","previous":"a loan from","count":3},{"next":"wished to take","previous":"was evident that","count":3},{"next":"he lightened the","previous":"his situation to","count":3},{"next":"reached the street","previous":"when saniel and","count":3},{"next":"he had hesitated","previous":"to appeal to","count":3},{"next":"and caffie he","previous":"already told to","count":3},{"next":"failed him cost","previous":"useless now since","count":3},{"next":"whose eyes were","previous":"silently walked by","count":3},{"next":"to have chosen","previous":"social weakness asked","count":3},{"next":"looking at the","previous":"rain again responded","count":3},{"next":"became definite at","previous":"vague fears of","count":3}]},{"secret_word":"gobillot","clues":[{"next":"the one whose","previous":"house mademoiselle reine","count":3},{"next":"a minor yet","previous":"to mademoiselle reine","count":3},{"next":"the landlady of","previous":"daughter of madame","count":3},{"next":"went to close","previous":"these words madame","count":3},{"next":"in person wearing","previous":"there was madame","count":3},{"next":"it may not","previous":"them by madame","count":3},{"next":"for a sweetheart","previous":"rather have reine","count":3},{"next":"was one of","previous":"much as madame","count":3},{"next":"an energetic woman","previous":"kept by madame","count":3},{"next":"are you certain","previous":"tell me madame","count":3},{"next":"pursing up her","previous":"pretty said mademoiselle","count":3},{"next":"will not think","previous":"nightingale sing mother","count":3},{"next":"s honor imposed","previous":"consideration due mademoiselle","count":1}]},{"secret_word":"godwin","clues":[{"next":"his friends etc","previous":"paul's text william","count":15},{"next":"godwin sells it","previous":"a grammar for","count":2},{"next":"and from godwin","previous":"from tuthil to","count":2},{"next":"sells it bound","previous":"grammar for godwin","count":2},{"next":"to tuthil and","previous":"godwin and from","count":2},{"next":"his friends and","previous":"kegan paul's william","count":2},{"next":"to his very","previous":"his great friend","count":1},{"next":"lived not in","previous":"her daughters and","count":1},{"next":"and all lamb's","previous":"were written to","count":1},{"next":"to mary shelley","previous":"letter from fanny","count":1},{"next":"dear godwin i","previous":"lamb to william","count":1},{"next":"i have found","previous":"william godwin dear","count":1}]},{"secret_word":"gondreville","clues":[{"next":"mystery a daughter","previous":"a princess the","count":12},{"next":"mystery the secrets","previous":"magic skin the","count":9},{"next":"mystery the member","previous":"of woman the","count":7},{"next":"mystery the firm","previous":"of eve the","count":7},{"next":"a constitutional peer","previous":"the comte de","count":2},{"next":"mystery letters of","previous":"the chouans the","count":2},{"next":"mystery beatrix leroi","previous":"old maid the","count":2},{"next":"s daughter she","previous":"little mme keller","count":2},{"next":"mystery a bachelor","previous":"ferdinand de the","count":2},{"next":"mystery the member","previous":"michu francois the","count":2},{"next":"mystery troisville guibelin","previous":"de beatrix the","count":1},{"next":"mystery beatrix navarreins","previous":"companion piece the","count":1}]},{"secret_word":"gontier","clues":[{"next":"herself opened the","previous":"his flight mademoiselle","count":3},{"next":"was superb at","previous":"old corneille mademoiselle","count":3},{"next":"with whom i","previous":"to have mademoiselle","count":3},{"next":"of the comedie","previous":"that of mademoiselle","count":3},{"next":"was gradually effaced","previous":"image of eugenie","count":3},{"next":"who violates no","previous":"fancy for eugenie","count":3},{"next":"in order to","previous":"however continued eugenie","count":3},{"next":"and there to","previous":"dwelling of eugenie","count":3},{"next":"the trouble of","previous":"door spared mademoiselle","count":3},{"next":"descended from it","previous":"road and eugenie","count":3},{"next":"was soon surrounded","previous":"deserved recalls eugenie","count":3},{"next":"and reiterated to","previous":"confided to eugenie","count":3},{"next":"with the marquis","previous":"liaison of eugenie","count":3}]},{"secret_word":"gorka","clues":[{"next":"and in what","previous":"the return of","count":3},{"next":"who did not","previous":"all replied madame","count":3},{"next":"and chapron might","previous":"a duel between","count":3},{"next":"as to her","previous":"to enlighten madame","count":3},{"next":"took offence at","previous":"it seems that","count":3},{"next":"at that moment","previous":"fate with which","count":3},{"next":"how would she","previous":"mother and boleslas","count":3},{"next":"then toward maitland","previous":"mother first toward","count":3},{"next":"against dorsenne the","previous":"savage aggression of","count":3},{"next":"excused herself on","previous":"saying that madame","count":3},{"next":"received no one","previous":"closed that maud","count":3},{"next":"below the wrist","previous":"ball had struck","count":3}]},{"secret_word":"grosset","clues":[{"next":"dunlap west th","previous":"popular copyrighted fiction","count":23},{"next":"dunlap publishers new","previous":"popular copyrighted fiction","count":15},{"next":"dunlap's list may","previous":"titles selected from","count":7},{"next":"dunlap's great books","previous":"a few of","count":6},{"next":"dunlap publishers new","previous":"by robert hichens","count":1},{"next":"dunlap new york","previous":"edition published by","count":1},{"next":"dunlap publishers new","previous":"grace livingston hill","count":1},{"next":"dunlap publishers copyright","previous":"carpenter new york","count":1},{"next":"dunlap publishers copyright","previous":"pictures new york","count":1},{"next":"dunlap publishers new","previous":"katharine newlin burt","count":1},{"next":"dunlap publishers copyright","previous":"hoskins new york","count":1},{"next":"dunlap publishers copyright","previous":"biggs new york","count":1},{"next":"dunlap publishers copyright","previous":"molnar new york","count":1}]},{"secret_word":"gutenberg","clues":[{"next":"online distributed proofreading","previous":"and the project","count":114},{"next":"also has an","previous":"net note project","count":37},{"next":"also has an","previous":"haines note project","count":36},{"next":"distributed proofreaders the","previous":"prepared by project","count":2},{"next":"edition to attach","previous":"the present project","count":1},{"next":"in text and","previous":"available from project","count":1},{"next":"distributed proofreaders the","previous":"allen and project","count":1},{"next":"distributed proofreaders black","previous":"prairie and project","count":1},{"next":"at the bottom","previous":"ebook and project","count":1},{"next":"beginners projects riikka","previous":"suzanne shell project","count":1},{"next":"distributed proofreaders his","previous":"raj and project","count":1},{"next":"distributed proofreaders anna","previous":"kirschner and project","count":1},{"next":"ebook of thomas","previous":"proofreaders the project","count":1}]},{"secret_word":"guy","clues":[{"next":"fairfax london dover","previous":"coke clifton to","count":25},{"next":"fairfax paris hotel","previous":"coke clifton to","count":4},{"next":"fairfax chateau de","previous":"coke clifton to","count":2},{"next":"with the bald","previous":"the funny old","count":1},{"next":"himself come out","previous":"saw the main","count":1},{"next":"was working for","previous":"we heard the","count":1},{"next":"in dere goin","previous":"say is dat","count":1},{"next":"on the ground","previous":"back at the","count":1},{"next":"in this company","previous":"he's the main","count":1},{"next":"of burgundy is","previous":"princess floripes and","count":1},{"next":"like yous wid","previous":"wot would a","count":1}]},{"secret_word":"gwilym","clues":[{"next":"the pride and","previous":"the great ab","count":3},{"next":"whom thou friend","previous":"the great ab","count":3},{"next":"what say you","previous":"not like ab","count":3},{"next":"had i not","previous":"respect to ab","count":3},{"next":"in my hands","previous":"found that ab","count":3},{"next":"that is said","previous":"ballads and ab","count":3},{"next":"and who had","previous":"ballads or ab","count":3},{"next":"to glorious john","previous":"ballads or ab","count":3},{"next":"they would not","previous":"ballads or ab","count":3},{"next":"but then i","previous":"ballads my ab","count":3},{"next":"of which you","previous":"translations from ab","count":3},{"next":"with quite as","previous":"translations from ab","count":3}]},{"secret_word":"hafner","clues":[{"next":"ardea and others","previous":"and her friends","count":3},{"next":"lowering his voice","previous":"for dorsenne returned","count":3},{"next":"should discover religious","previous":"is that papa","count":3},{"next":"should call her","previous":"it required that","count":3},{"next":"to go to","previous":"i promised poor","count":3},{"next":"is in the","previous":"know when a","count":3},{"next":"has not already","previous":"last copy if","count":3},{"next":"rendered in evitable","previous":"toward ardea and","count":3},{"next":"as a tool","previous":"agent who served","count":3},{"next":"still wants it","previous":"borgognona if mademoiselle","count":3},{"next":"whom his daughter's","previous":"of that knave","count":2},{"next":"and prince d'ardea","previous":"pointing to fanny","count":2}]},{"secret_word":"haines","clues":[{"next":"note project gutenberg","previous":"prepared by al","count":36},{"next":"love to the","previous":"the reverend mr","count":1},{"next":"love raises high","previous":"the reverend mr","count":1},{"next":"and sell himself","previous":"is worth to","count":1},{"next":"said amid the","previous":"ancient irish myth","count":1},{"next":"said thoughtfully lifting","previous":"long way off","count":1},{"next":"of denver jerked","previous":"get through neddy","count":1},{"next":"the conquest of","previous":"version by al","count":1},{"next":"desiderius erasmus the","previous":"version by al","count":1},{"next":"said pinching his","previous":"id e fixe","count":1},{"next":"gravely gazed down","previous":"mulligan gaily and","count":1},{"next":"of the timber","previous":"'lectric railway and","count":1}]},{"secret_word":"halevy","clues":[{"next":"the celebrated author","previous":"father was leon","count":3},{"next":"ludovic halevy was","previous":"french academy ludovic","count":3},{"next":"has not published","previous":"time i think","count":3},{"next":"rather abruptly abandoned","previous":"twenty years when","count":3},{"next":"reaped a great","previous":"others assert that","count":3},{"next":"who may be","previous":"farther than ludovic","count":3},{"next":"with a preface","previous":"constantin by ludovic","count":3},{"next":"was born in","previous":"ludovic halevy ludovic","count":3},{"next":"resigned giving up","previous":"morny died in","count":3},{"next":"near the opera","previous":"of 'l'actualite' rue","count":2},{"next":"and becque with","previous":"dumas emile augier","count":1},{"next":"jacques hall pauline","previous":"hadrian hale philip","count":1}]},{"secret_word":"heloise","clues":[{"next":"placing her five","previous":"and madame corrected","count":3},{"next":"cut short the","previous":"the entrance of","count":3},{"next":"won six hundred","previous":"the sixth round","count":3},{"next":"the smile of","previous":"the sensibility of","count":3},{"next":"virot the first","previous":"his right sat","count":3},{"next":"seated herself at","previous":"to be dealt","count":3},{"next":"used to do","previous":"as that fat","count":3},{"next":"who had been","previous":"their feet and","count":3},{"next":"to go with","previous":"fanny i wished","count":3},{"next":"throw herself into","previous":"like julie and","count":2},{"next":"and still wearing","previous":"of la nouvelle","count":1},{"next":"his wife's indignation","previous":"of abelard and","count":1}]},{"secret_word":"higham","clues":[{"next":"by rochester kent","previous":"gad's hill place","count":78},{"next":"station in a","previous":"and which reached","count":1},{"next":"escorted by mr","previous":"for hurry gertie","count":1},{"next":"good evening in","previous":"he bade miss","count":1},{"next":"that one profession","previous":"out to miss","count":1},{"next":"where the carriage","previous":"little country station","count":1},{"next":"and myself will","previous":"am sure miss","count":1},{"next":"had to put","previous":"fate and gertie","count":1},{"next":"had been guilty","previous":"believe that miss","count":1},{"next":"faced each other","previous":"madame and miss","count":1},{"next":"was called frequently","previous":"madame or miss","count":1},{"next":"during the brief","previous":"behaviour of miss","count":1},{"next":"took the label","previous":"forewoman and miss","count":1}]},{"secret_word":"honorine","clues":[{"next":"the seamy side","previous":"courtesan s life","count":7},{"next":"the seamy side","previous":"a courtesan's life","count":4},{"next":"ward and only","previous":"of the sainte","count":2},{"next":"ward of which","previous":"of the sainte","count":2},{"next":"ward he became","previous":"of the sainte","count":2},{"next":"ward only beheld","previous":"of the sainte","count":2},{"next":"ward she gave","previous":"in the sainte","count":2},{"next":"ward they found","previous":"in the sainte","count":2},{"next":"ward at once","previous":"to the sainte","count":2},{"next":"beatrix turquet marguerite","previous":"daughter of eve","count":2},{"next":"ward was now","previous":"her the sainte","count":2},{"next":"in its columns","previous":"presse by publishing","count":1}]},{"secret_word":"html","clues":[{"next":"version of this","previous":"also has an","count":95},{"next":"file produced by","previous":"by stephen leary","count":1},{"next":"version for pagenumbers","previous":"was prenicious see","count":1},{"next":"version of the","previous":"on 'long s'","count":1},{"next":"version of this","previous":"found in the","count":1},{"next":"version for detail","previous":"please see the","count":1},{"next":"version of the","previous":"code of the","count":1},{"next":"file produced by","previous":"distributed proofreading team","count":1},{"next":"version of this","previous":"inserted into the","count":1},{"next":"version produced by","previous":"revised edition and","count":1}]},{"secret_word":"ii","clues":[{"next":"chapter iii chapter","previous":"chapter i chapter","count":31},{"next":"which treats of","previous":"la mancha chapter","count":1},{"next":"a where the","previous":"by tablet spartali","count":1},{"next":"the torn scrap","previous":"the woods part","count":1},{"next":"which treats of","previous":"his malady chapter","count":1},{"next":"the lion's eye","previous":"at the inn","count":1},{"next":"but from this","previous":"death of philip","count":1},{"next":"from whom he","previous":"those of charles","count":1},{"next":"metz with its","previous":"ii lorraine chapter","count":1},{"next":"chapter i of","previous":"conclusion contents volume","count":1},{"next":"seems to show","previous":"paradise in genesis","count":1},{"next":"tiglath pileser iii","previous":"inscriptions of shalmaneser","count":1},{"next":"sennacherib esarhaddon and","previous":"pileser iii sargon","count":1}]},{"secret_word":"impossible","clues":[{"next":"for him to","previous":"would have been","count":23},{"next":"to feel any","previous":"that it was","count":2},{"next":"for me to","previous":"have rendered it","count":2},{"next":"for him so","previous":"was now clearly","count":1},{"next":"that facing the","previous":"it is not","count":1},{"next":"montana but was","previous":"far off and","count":1},{"next":"for newport so","previous":"so lute ly","count":1},{"next":"but every wise","previous":"not only otherwise","count":1},{"next":"fanny was so","previous":"them was almost","count":1},{"next":"he would give","previous":"would make it","count":1},{"next":"and i'm going","previous":"it's made things","count":1}]},{"secret_word":"includes","clues":[{"next":"the original illustrations","previous":"this file which","count":74},{"next":"the accusation that","previous":"clouds' of aristophanes","count":2},{"next":"but thirty six","previous":"the british fleet","count":1},{"next":"the apple also","previous":"the rosaceae which","count":1},{"next":"ma's and psyche's","previous":"all mine it","count":1},{"next":"society's history and","previous":"a plan which","count":1},{"next":"the genius of","previous":"an epoch necessarily","count":1},{"next":"a noble fragment","previous":"but it also","count":1},{"next":"in it the","previous":"as goethe said","count":1},{"next":"a general habit","previous":"far as it","count":1},{"next":"the power to","previous":"science of detection","count":1},{"next":"a printer four","previous":"albion this calculation","count":1}]},{"secret_word":"institute","clues":[{"next":"for historical microreproductions","previous":"by the canadian","count":19},{"next":"might yet be","previous":"like the apollinean","count":2},{"next":"in the same","previous":"of the french","count":1},{"next":"was adorned with","previous":"of some learned","count":1},{"next":"and as devotees","previous":"at the art","count":1},{"next":"next week that","previous":"to the art","count":1},{"next":"then in the","previous":"member of the","count":1},{"next":"and the british","previous":"from the french","count":1},{"next":"and painted very","previous":"course in cooper","count":1},{"next":"perhaps he'd join","previous":"class at the","count":1},{"next":"comparisons in colouring","previous":"pictures we naturally","count":1},{"next":"well they're fine","previous":"classes at the","count":1}]},{"secret_word":"internet","clues":[{"next":"archive american libraries","previous":"available by the","count":29},{"next":"archive canadian libraries","previous":"available by the","count":10},{"next":"over paper publication","previous":"the advantages of","count":5},{"next":"archive american libraries","previous":"are available through","count":3},{"next":"archive american libraries","previous":"made available by","count":3},{"next":"theology resources site","previous":"saint john's university","count":2},{"next":"user and text","previous":"was the biggest","count":1},{"next":"and assumed it","previous":"heard of the","count":1},{"next":"it's got me","previous":"web and the","count":1},{"next":"archive illustration richmond","previous":"available by the","count":1},{"next":"archive a hand","previous":"available at the","count":1},{"next":"providers instantaneous messages","previous":"cellular phones and","count":1}]},{"secret_word":"iv","clues":[{"next":"chapter v chapter","previous":"chapter iii chapter","count":29},{"next":"v vi vii","previous":"i ii iii","count":9},{"next":"the attack on","previous":"the inn part","count":1},{"next":"of what happened","previous":"a knight chapter","count":1},{"next":"cheyne row to","previous":"to london chapter","count":1},{"next":"volume v letter","previous":"end of volume","count":1},{"next":"letter lxi coke","previous":"volume iii volume","count":1},{"next":"volume v volume","previous":"volume iii volume","count":1},{"next":"the oak parlour","previous":"marquis at night","count":1},{"next":"in which sancho","previous":"samson carrasco chapter","count":1},{"next":"and there was","previous":"cult for george","count":1},{"next":"juvenile court v","previous":"clarkes at home","count":1}]},{"secret_word":"ix","clues":[{"next":"chapter x chapter","previous":"chapter viii chapter","count":25},{"next":"x xi xii","previous":"vi vii viii","count":8},{"next":"carlyle's political philosophy","previous":"and historian chapter","count":1},{"next":"poetic diction laodamia","previous":"the excursion chapter","count":1},{"next":"peppajee jim heap","previous":"the amiable angler","count":1},{"next":"chapter x epilogue","previous":"chapter viii chapter","count":1},{"next":"recollections of a","previous":"viii green lights","count":1},{"next":"buttons x the","previous":"viii ambition stirs","count":1},{"next":"an unlikely tale","previous":"duel with valencia","count":1},{"next":"wherein is related","previous":"del toboso chapter","count":1},{"next":"in which is","previous":"fitly recorded chapter","count":1},{"next":"fired on the","previous":"balcony where charles","count":1}]},{"secret_word":"jocquelet","clues":[{"next":"absolutely unknown too","previous":"an exceptional grace","count":3},{"next":"who played that","previous":"his drama of","count":3},{"next":"who had just","previous":"doubt it for","count":3},{"next":"had recited at","previous":"she said that","count":3},{"next":"in the theatres","previous":"went to see","count":3},{"next":"from making himself","previous":"right to dissuade","count":3},{"next":"by amedee obtained","previous":"workman offered to","count":3},{"next":"who has made","previous":"principal role for","count":3},{"next":"who more and","previous":"aristocratic face of","count":3},{"next":"had made the","previous":"animation and when","count":3},{"next":"was working at","previous":"violette incited by","count":3},{"next":"recited your 'sebastopol'","previous":"of marshal lefievre","count":2},{"next":"the latter recited","previous":"amedee's meeting with","count":2}]},{"secret_word":"joinville","clues":[{"next":"sur oise for","previous":"the castle of","count":3},{"next":"you know under","previous":"the park of","count":3},{"next":"before the marble","previous":"the lindens of","count":3},{"next":"castle that he","previous":"was at the","count":3},{"next":"and that during","previous":"later go to","count":3},{"next":"crown she said","previous":"it is the","count":3},{"next":"she said the","previous":"my father bought","count":3},{"next":"since all is","previous":"yes as at","count":3},{"next":"delicate and poor","previous":"careful languished at","count":3},{"next":"bought restored and","previous":"historical castle of","count":3},{"next":"till a week","previous":"we stayed at","count":1},{"next":"where madame gautier","previous":"straight on to","count":1}]},{"secret_word":"jonquille","clues":[{"next":"campanule or touki","previous":"the mammas of","count":4},{"next":"touki all your","previous":"going together campanule","count":4},{"next":"taking the air","previous":"however is madame","count":4},{"next":"who is even","previous":"wife then madame","count":4},{"next":"his wife arrived","previous":"n and madame","count":4},{"next":"toukisan and campanule","previous":"the triomphante and","count":3},{"next":"with the friend","previous":"san campanule and","count":3},{"next":"really look like","previous":"evening chrysantheme and","count":3},{"next":"touki san and","previous":"the triomphante and","count":1},{"next":"with 'the friend","previous":"san campanule and","count":1},{"next":"really look like","previous":"chrysanth me and","count":1}]},{"secret_word":"jugan","clues":[{"next":"and supplicated her","previous":"de la roche","count":3},{"next":"with a shade","previous":"de la roche","count":3},{"next":"to reproach herself","previous":"de la roche","count":3},{"next":"finally offered to","previous":"de la roche","count":3},{"next":"had persuaded herself","previous":"de la roche","count":3},{"next":"had laid there","previous":"de la roche","count":3},{"next":"had broken with","previous":"de la roche","count":3},{"next":"who had consulted","previous":"de la roche","count":3},{"next":"who saw her","previous":"de la roche","count":3},{"next":"did not shrink","previous":"de la roche","count":3},{"next":"judged the best","previous":"de la roche","count":3},{"next":"hated her niece","previous":"de la roche","count":3},{"next":"dryly if this","previous":"de la roche","count":3}]},{"secret_word":"jupille","clues":[{"next":"still carrying his","previous":"and led by","count":3},{"next":"and i have","previous":"the old clerk","count":3},{"next":"i shut the","previous":"a chair monsieur","count":3},{"next":"else he would","previous":"a bite said","count":3},{"next":"suddenly found himself","previous":"at this point","count":3},{"next":"has ordered dinner","previous":"my dear mouillard","count":3},{"next":"i accept the","previous":"you please monsieur","count":3},{"next":"with an east","previous":"again some day","count":3},{"next":"who had started","previous":"sceaux to meet","count":3},{"next":"who wept as","previous":"flamaran and sidonie","count":3},{"next":"it's all right","previous":"it's all right","count":2},{"next":"it s all","previous":"s all right","count":1}]},{"secret_word":"justus","clues":[{"next":"hafner had indeed","previous":"by which baron","count":3},{"next":"hafner was inscribed","previous":"a dutch protestant","count":3},{"next":"hafner the thief","previous":"his second monsieur","count":3},{"next":"had not less","previous":"at twenty seven","count":3},{"next":"more beautiful than","previous":"daughter of baron","count":3},{"next":"hafner german austrian","previous":"is this baron","count":3},{"next":"hafner and his","previous":"several of them","count":3},{"next":"hafner only represents","previous":"de montfanon while","count":3},{"next":"was very young","previous":"latter died when","count":3},{"next":"euler and the","previous":"with him were","count":1},{"next":"miles forman faire","previous":"richard reynolds and","count":1},{"next":"olivier lavinia mary","previous":"rodney olivier victor","count":1}]},{"secret_word":"key","clues":[{"next":"in his pocket","previous":"and put the","count":23},{"next":"in the door","previous":"was trying the","count":1},{"next":"we are apt","previous":"in the high","count":1},{"next":"on the nail","previous":"in hang the","count":1},{"next":"and went in","previous":"with a master","count":1},{"next":"upon these treasures","previous":"to turn a","count":1},{"next":"and let it","previous":"it to the","count":1},{"next":"into a green","previous":"she fitted the","count":1},{"next":"to his expression","previous":"me is the","count":1},{"next":"of the garage","previous":"i have the","count":1},{"next":"and he at","previous":"room with a","count":1},{"next":"of the street","previous":"pocket lay the","count":1}]},{"secret_word":"knight's","clues":[{"next":"conjuring me to","previous":"but upon the","count":5},{"next":"head had hung","previous":"so that the","count":5},{"next":"family and to","previous":"servant in the","count":5},{"next":"behaviour in them","previous":"adventures with the","count":5},{"next":"determination because neither","previous":"dissatisfied with the","count":5},{"next":"directions to add","previous":"painter by the","count":5},{"next":"proposal we rid","previous":"pleased with the","count":4},{"next":"shakespeare hume and","previous":"the waverley novels","count":1},{"next":"tomb sobbing and","previous":"of the young","count":1},{"next":"life of wordsworth","previous":"may from professor","count":1},{"next":"text in his","previous":"print from professor","count":1},{"next":"'taste' in which","previous":"review' on payne","count":1}]},{"secret_word":"knock","clues":[{"next":"at the door","previous":"there was a","count":146},{"next":"her head against","previous":"up she d","count":1},{"next":"came on his","previous":"this development another","count":1},{"next":"one another to","previous":"to fight and","count":1},{"next":"and go in","previous":"who come and","count":1},{"next":"at our life","previous":"it comes to","count":1},{"next":"you to pieces","previous":"these bulls will","count":1},{"next":"under i say","previous":"we going to","count":1},{"next":"the dust out","previous":"will serve to","count":1},{"next":"at the door","previous":"then came the","count":1},{"next":"my title on","previous":"afraid this will","count":1},{"next":"mademoiselle and ask","previous":"inn he said","count":1}]},{"secret_word":"lambernier","clues":[{"next":"who had suddenly","previous":"the saints stammered","count":3},{"next":"took to escape","previous":"the road that","count":3},{"next":"whispered the notary","previous":"of this man","count":3},{"next":"may have been","previous":"a weapon which","count":3},{"next":"but the consideration","previous":"his meeting with","count":3},{"next":"up for he","previous":"over and raised","count":3},{"next":"a few days","previous":"little altercation with","count":3},{"next":"said he to","previous":"you are mistaken","count":3},{"next":"who during this","previous":"then looked at","count":3},{"next":"was not disturbed","previous":"coming storm but","count":3},{"next":"is it not","previous":"devil of a","count":3},{"next":"had told him","previous":"woodwork of which","count":3}]},{"secret_word":"lampron","clues":[{"next":"painter in ordinary","previous":"and mine sylvestre","count":3},{"next":"in a large","previous":"a letter from","count":3},{"next":"for his generosity","previous":"in thanking monsieur","count":3},{"next":"at work his","previous":"my slumbering furniture","count":3},{"next":"who was plainly","previous":"i was watching","count":3},{"next":"who had forgotten","previous":"letter was from","count":3},{"next":"detained by my","previous":"get away himself","count":3},{"next":"for a moment","previous":"get hold of","count":3},{"next":"who was beginning","previous":"explanation whatever replied","count":3},{"next":"had sketched in","previous":"market jeanne whom","count":3},{"next":"wrote did not","previous":"precincts of which","count":3}]},{"secret_word":"langres","clues":[{"next":"in a shaky","previous":"the plain above","count":3},{"next":"claudet enrolled in","previous":"in arriving at","count":3},{"next":"in the afternoon","previous":"he arrived at","count":3},{"next":"and consulted an","previous":"had been to","count":3},{"next":"julien completely lost","previous":"brought him from","count":3},{"next":"to enroll myself","previous":"going now to","count":3},{"next":"the bells of","previous":"mountain gorges in","count":3},{"next":"and the ancient","previous":"level plain of","count":3},{"next":"to bar sur","previous":"communication that from","count":3},{"next":"spring can hardly","previous":"mountainous region of","count":3},{"next":"the abb parisis","previous":"the bishop of","count":1},{"next":"to dijon the","previous":"railway embankment from","count":1}]},{"secret_word":"lariviere","clues":[{"next":"did you see","previous":"la briche asked","count":3},{"next":"in that box","previous":"the hall see","count":3},{"next":"standing at his","previous":"the parquette general","count":3},{"next":"with a pretty","previous":"of the hall","count":3},{"next":"i had just","previous":"when i met","count":3},{"next":"approached with heavy","previous":"powerful breathing general","count":3},{"next":"minister of war","previous":"your friend old","count":3},{"next":"the present army","previous":"you do replied","count":3},{"next":"extended his hand","previous":"passed before them","count":3},{"next":"told you first","previous":"sorry that general","count":3},{"next":"perhaps vence or","previous":"princess seniavine general","count":3},{"next":"came out of","previous":"schmoll and general","count":3}]},{"secret_word":"legislatif","clues":[{"next":"and the old","previous":"of the corps","count":3},{"next":"and when he","previous":"of the corps","count":3},{"next":"and had won","previous":"of the corps","count":3},{"next":"are shamelessly harassed","previous":"of the corps","count":3},{"next":"as for the","previous":"for the corps","count":3},{"next":"where his place","previous":"in the corps","count":3},{"next":"where he assumed","previous":"in the corps","count":3},{"next":"and they had","previous":"to the corps","count":3},{"next":"of the empire","previous":"to the corps","count":3},{"next":"and in the","previous":"of the corps","count":1},{"next":"a dozen or","previous":"of the corps","count":1},{"next":"his mother on","previous":"of the corps","count":1},{"next":"the council of","previous":"senate the corps","count":1}]},{"secret_word":"lenaieff","clues":[{"next":"because of the","previous":"was irritated against","count":3},{"next":"said henri to","previous":"to you general","count":3},{"next":"his rival he","previous":"second place after","count":3},{"next":"for otherwise i","previous":"still less said","count":3},{"next":"have you not","previous":"you captain said","count":3},{"next":"feeling certain that","previous":"pass it with","count":3},{"next":"that she would","previous":"eager request of","count":3},{"next":"in full uniform","previous":"de camp general","count":3},{"next":"the lisieux the","previous":"de vermont constantin","count":3},{"next":"who is hastening","previous":"comes your friend","count":3},{"next":"on the contrary","previous":"neighbor to whom","count":3},{"next":"and the chevalier","previous":"montgeron between general","count":3}]},{"secret_word":"leontine","clues":[{"next":"and considering at","previous":"the care of","count":3},{"next":"told him that","previous":"his supposed father","count":3},{"next":"a daughter but","previous":"to him and","count":3},{"next":"though he had","previous":"that lived with","count":3},{"next":"considering how incapable","previous":"their usual intimacy","count":3},{"next":"than by marrying","previous":"my gratitude to","count":3},{"next":"recommended to him","previous":"every thing which","count":3},{"next":"to repair to","previous":"sudden summons from","count":3},{"next":"and himself to","previous":"poor estate for","count":3},{"next":"as his son","previous":"bred up with","count":3},{"next":"as my circumstances","previous":"to be his","count":2},{"next":"and sent her","previous":"black gown to","count":1}]},{"secret_word":"leopardi","clues":[{"next":"in so imperative","previous":"of the rue","count":3},{"next":"to provoke your","previous":"to the rue","count":3},{"next":"madame maitland who","previous":"to the rue","count":3},{"next":"and he settled","previous":"on the rue","count":3},{"next":"after having seen","previous":"on the rue","count":3},{"next":"she walked on","previous":"on the rue","count":3},{"next":"and in that","previous":"entered the rue","count":3},{"next":"to provoke his","previous":"toward the rue","count":3},{"next":"in which was","previous":"watch the rue","count":3},{"next":"s fine ode","previous":"he knew well","count":1},{"next":"s grand ode","previous":"words selected from","count":1},{"next":"he was always","previous":"much influenced by","count":1},{"next":"into laughter or","previous":"bitter lips of","count":1}]},{"secret_word":"lescande","clues":[{"next":"came back suddenly","previous":"of young madame","count":3},{"next":"on the threshold","previous":"was stopped by","count":3},{"next":"as a compliment","previous":"an architect named","count":3},{"next":"to take them","previous":"daughter prevailed upon","count":3},{"next":"and a young","previous":"little like madame","count":3},{"next":"to whom he","previous":"not to madame","count":3},{"next":"the language and","previous":"held toward madame","count":3},{"next":"should be able","previous":"wife of simple","count":3},{"next":"in her coquettish","previous":"interested in madame","count":3},{"next":"had risen before","previous":"ghost of madame","count":3},{"next":"meanwhile sitting with","previous":"dazzle the daughter","count":3},{"next":"only on her","previous":"expatiate to madame","count":3},{"next":"felt the exhilarating","previous":"camors and madame","count":3}]},{"secret_word":"lisbeth","clues":[{"next":"he said with","previous":"up the joist","count":3},{"next":"kept an eye","previous":"a stocking while","count":3},{"next":"looked at sam'l","previous":"his chair and","count":3},{"next":"was unselfish in","previous":"him and though","count":3},{"next":"did not expect","previous":"time and indeed","count":3},{"next":"or the lassie's","previous":"question of either","count":3},{"next":"did the weaver","previous":"neither bell nor","count":3},{"next":"trying to look","previous":"table sam'l said","count":3},{"next":"an' mair said","previous":"there's a' that","count":3},{"next":"fargus said it","previous":"penny wedding and","count":3},{"next":"fargus no to","previous":"ower lang wi'","count":3},{"next":"i ha' got","previous":"a clear solemnity","count":1}]},{"secret_word":"lisieux","clues":[{"next":"and madame de","previous":"by madame de","count":3},{"next":"in another the","previous":"the comtesse de","count":3},{"next":"taking a pen","previous":"the comtesse de","count":3},{"next":"leaning upon m","previous":"the comtesse de","count":3},{"next":"or of madame","previous":"of madame de","count":3},{"next":"and madame de","previous":"as madame de","count":3},{"next":"in a confidential","previous":"said madame de","count":3},{"next":"who had been","previous":"inquired madame de","count":3},{"next":"the nointels edmond","previous":"constantin lenaieff the","count":3},{"next":"and madame de","previous":"montgeron madame de","count":3},{"next":"know nothing of","previous":"the people of","count":1}]},{"secret_word":"lizerolles","clues":[{"next":"and jacqueline is","previous":"the year at","count":3},{"next":"bloomed that year","previous":"the roses at","count":3},{"next":"rather than go","previous":"to stay at","count":3},{"next":"would be left","previous":"to tonquin that","count":3},{"next":"which her perverseness","previous":"her stay at","count":3},{"next":"by the necessity","previous":"being detained at","count":3},{"next":"stupid he could","previous":"not to find","count":3},{"next":"every day as","previous":"come back to","count":3},{"next":"which was not","previous":"seeking refuge at","count":3},{"next":"whose autumnal beauties","previous":"better off at","count":3},{"next":"october my dear","previous":"expected to receive","count":3},{"next":"of having him","previous":"keeping him at","count":3},{"next":"and browse where","previous":"flowery meads of","count":3}]},{"secret_word":"longueval","clues":[{"next":"while placed behind","previous":"the church of","count":3},{"next":"the trees of","previous":"the park of","count":3},{"next":"was here he","previous":"when madame de","count":3},{"next":"loulou had very","previous":"had lived at","count":3},{"next":"the same as","previous":"great salon at","count":3},{"next":"a month ago","previous":"she came to","count":3},{"next":"the turners and","previous":"would bring to","count":3},{"next":"and there would","previous":"would arrive at","count":3},{"next":"pray for them","previous":"new mistresses of","count":3},{"next":"that the luxury","previous":"new splendors of","count":3},{"next":"for ten days","previous":"going back to","count":3},{"next":"and dine at","previous":"last day at","count":3},{"next":"and shall not","previous":"install myself at","count":3}]},{"secret_word":"lunacy","clues":[{"next":"lost illusions a","previous":"the commission in","count":12},{"next":"scenes from a","previous":"the commission in","count":8},{"next":"taken out against","previous":"a commission of","count":2},{"next":"inspires since this","previous":"the compassion which","count":1},{"next":"she tore her","previous":"the height of","count":1},{"next":"it is hard","previous":"the charge of","count":1},{"next":"was taken out","previous":"a commission of","count":1},{"next":"to declare charlotte","previous":"a commission of","count":1},{"next":"which made his","previous":"amidst all this","count":1},{"next":"and is employ'd","previous":"recovered from his","count":1},{"next":"and love and","previous":"classes it with","count":1},{"next":"in america to","previous":"invariable sign of","count":1},{"next":"of the daughter","previous":"heartbreak and gentle","count":1}]},{"secret_word":"manette","clues":[{"next":"he left vivey","previous":"the lamentations of","count":3},{"next":"sejournant was busy","previous":"the kitchen where","count":3},{"next":"the hunting stories","previous":"the gossipings of","count":3},{"next":"on his conscience","previous":"this he had","count":3},{"next":"and her son","previous":"real position of","count":3},{"next":"sejournant prostrate on","previous":"service was intoned","count":3},{"next":"could not bear","previous":"fact was that","count":3},{"next":"that he would","previous":"room abruptly told","count":3},{"next":"sejournant and her","previous":"steady hostility of","count":3},{"next":"had employed all","previous":"breakfast on which","count":3},{"next":"as gentle as","previous":"'grand chasserot' made","count":2},{"next":"salomon be the","previous":"age and if","count":1}]},{"secret_word":"marillac","clues":[{"next":"whose sparkling eye","previous":"the guests was","count":3},{"next":"mute and speechless","previous":"when he saw","count":3},{"next":"to his room","previous":"who were carrying","count":3},{"next":"away christian went","previous":"who were carrying","count":3},{"next":"has not a","previous":"first this monsieur","count":3},{"next":"he seized hold","previous":"attempt only irritated","count":3},{"next":"from the other","previous":"now notary said","count":3},{"next":"with superb disdain","previous":"me alone replied","count":3},{"next":"without stopping at","previous":"you like said","count":3},{"next":"by his friend","previous":"attentions lavished upon","count":3},{"next":"emptied glass after","previous":"drunk as he","count":3},{"next":"as if he","previous":"suddenly looking at","count":3},{"next":"hold your tongue","previous":"beg of you","count":3}]},{"secret_word":"marmet","clues":[{"next":"said that m","previous":"the good madame","count":3},{"next":"for monsieur choulette","previous":"for good madame","count":3},{"next":"at the house","previous":"friend and madame","count":3},{"next":"but immediately he","previous":"friend of madame","count":3},{"next":"with tranquil vigilance","previous":"while good madame","count":3},{"next":"she told her","previous":"she kissed madame","count":3},{"next":"explained how finding","previous":"theatre and madame","count":3},{"next":"who were waiting","previous":"bell and madame","count":3},{"next":"went to look","previous":"bell and madame","count":3},{"next":"coming out of","previous":"bell and madame","count":3},{"next":"along the journey","previous":"surprised when madame","count":3},{"next":"was to embroider","previous":"cushion which madame","count":3}]},{"secret_word":"meehan","clues":[{"next":"and the online","previous":"robert cicconetti mary","count":6},{"next":"and the project","previous":"suzanne shell mary","count":4},{"next":"and the online","previous":"suzanne shell mary","count":4},{"next":"and pg distributed","previous":"juliet sutherland mary","count":3},{"next":"and the project","previous":"david clarke mary","count":3},{"next":"and the online","previous":"david clarke mary","count":3},{"next":"and distributed proofreaders","previous":"jonathan ingram mary","count":2},{"next":"and pg distributed","previous":"suzanne shell mary","count":2},{"next":"and pg distributed","previous":"produced by mary","count":1},{"next":"david garcia and","previous":"juliet sutherland mary","count":1},{"next":"and the project","previous":"charles aldarondo mary","count":1},{"next":"and project gutenberg","previous":"tiffany vergon mary","count":1},{"next":"charles franks and","previous":"suzanne shell mary","count":1}]},{"secret_word":"menil","clues":[{"next":"who was bowing","previous":"the shadow le","count":3},{"next":"had introduced to","previous":"men whom le","count":3},{"next":"the sentiment of","previous":"had against le","count":3},{"next":"had been invited","previous":"she feared le","count":3},{"next":"the blue sea","previous":"news of le","count":3},{"next":"would ask his","previous":"if monsieur le","count":3},{"next":"said miss bell","previous":"oh monsieur le","count":3},{"next":"i know you","previous":"oh monsieur le","count":3},{"next":"at the races","previous":"shall meet le","count":3},{"next":"who having followed","previous":"recognized robert le","count":3}]},{"secret_word":"micheline","clues":[{"next":"and serge in","previous":"the house abandoned","count":3},{"next":"the stranger seemed","previous":"the sight of","count":3},{"next":"full of pity","previous":"the arms which","count":3},{"next":"was in agony","previous":"the room where","count":3},{"next":"and with a","previous":"his arms round","count":3},{"next":"left him to","previous":"had sped since","count":3},{"next":"in a furious","previous":"be bold continued","count":3},{"next":"who loved serge","previous":"she thought of","count":3},{"next":"answered serge with","previous":"i have none","count":3},{"next":"and opening the","previous":"thought it was","count":3},{"next":"entered holding in","previous":"door opened and","count":3},{"next":"and beseechingly stretched","previous":"madame cayrol approached","count":3}]},{"secret_word":"mignon","clues":[{"next":"the secrets of","previous":"at sceaux modeste","count":7},{"next":"scenes from a","previous":"government clerks modeste","count":7},{"next":"jealousies of a","previous":"a princess modeste","count":5},{"next":"the secrets of","previous":"at sceaux modest","count":3},{"next":"the muse of","previous":"a princess modeste","count":2},{"next":"cousin betty lenoncourt","previous":"hated son modeste","count":2},{"next":"vient fouler notre","previous":"lorsque ton pied","count":2},{"next":"les huguenots and","previous":"the musical trinity","count":1},{"next":"the harpist in","previous":"of goethe to","count":1},{"next":"and at the","previous":"warm as goethe's","count":1},{"next":"gaudissart ii a","previous":"other books modeste","count":1},{"next":"balzac connects with","previous":"beatrix and modeste","count":1},{"next":"another study of","previous":"courtesan's life modeste","count":1}]},{"secret_word":"mirouet","clues":[{"next":"a marriage settlement","previous":"country town ursule","count":9},{"next":"a woman of","previous":"the peasantry ursule","count":5},{"next":"eugenie grandet the","previous":"s establishment ursule","count":5},{"next":"a man of","previous":"goriot gobseck ursule","count":4},{"next":"a marriage settlement","previous":"father goriot ursule","count":2},{"next":"a woman of","previous":"life ferragus ursule","count":2},{"next":"maufrigneuse duchesse de","previous":"s life ursule","count":2},{"next":"a woman of","previous":"of langeais ursule","count":1},{"next":"promissory notes bills","previous":"upon in ursule","count":1},{"next":"eugenie grandet the","previous":"government clerks ursule","count":1},{"next":"one of those","previous":"have written ursule","count":1},{"next":"and les memoires","previous":"de garcon ursule","count":1},{"next":"magus elie the","previous":"courtesan's life ursule","count":1}]},{"secret_word":"modeste","clues":[{"next":"mignon scenes from","previous":"the government clerks","count":7},{"next":"mignon the secrets","previous":"ball at sceaux","count":7},{"next":"mignon jealousies of","previous":"of a princess","count":5},{"next":"mignon scenes from","previous":"side of history","count":4},{"next":"mignon scenes from","previous":"bachelor s establishment","count":4},{"next":"mignon cousin betty","previous":"the hated son","count":2},{"next":"mignon the muse","previous":"of a princess","count":2},{"next":"maria beck n","previous":"her name was","count":2},{"next":"mignon another study","previous":"a courtesan's life","count":1},{"next":"mignon gaudissart ii","previous":"among other books","count":1},{"next":"beck that you","previous":"what i told","count":1},{"next":"maria beck that","previous":"re silas and","count":1},{"next":"mignon balzac connects","previous":"femme beatrix and","count":1}]},{"secret_word":"moll","clues":[{"next":"white and has","previous":"the name of","count":4},{"next":"is said often","previous":"for besides that","count":4},{"next":"white has been","previous":"in the stable","count":4},{"next":"white had been","previous":"to see if","count":4},{"next":"white in it","previous":"has not a","count":4},{"next":"had been often","previous":"me that old","count":4},{"next":"white will needs","previous":"i made to","count":4},{"next":"white and will","previous":"thy conversations with","count":4},{"next":"white had followed","previous":"a report that","count":2},{"next":"white her self","previous":"a report as","count":2},{"next":"white is at","previous":"should have it","count":2},{"next":"is past all","previous":"so white footed","count":1}]},{"secret_word":"montfanon","clues":[{"next":"did she not","previous":"the mother asked","count":3},{"next":"mechanically repeated as","previous":"of remorse which","count":3},{"next":"for one fifth","previous":"to monsieur de","count":3},{"next":"bought to vex","previous":"which your friend","count":3},{"next":"which you do","previous":"is one interrupted","count":3},{"next":"took me there","previous":"my old friend","count":3},{"next":"was here to","previous":"wish monsieur de","count":3},{"next":"adding with ill","previous":"i hope replied","count":3},{"next":"and i set","previous":"will monsieur de","count":3},{"next":"perceived large tears","previous":"turning again toward","count":3},{"next":"and the doctor","previous":"gayly leaning on","count":3},{"next":"had advised in","previous":"drawing back as","count":3}]},{"secret_word":"montgeron","clues":[{"next":"where morning and","previous":"the hotel de","count":3},{"next":"had a double","previous":"the hotel de","count":3},{"next":"they swear by","previous":"the hotel de","count":3},{"next":"arriving just in","previous":"the hotel de","count":3},{"next":"had no children","previous":"the duchesse de","count":3},{"next":"who had passed","previous":"the duchesse de","count":3},{"next":"between general lenaieff","previous":"the duchesse de","count":3},{"next":"and the marquis","previous":"the duc de","count":3},{"next":"was destined to","previous":"the duc de","count":3},{"next":"when the train","previous":"said madame de","count":3},{"next":"who had known","previous":"than madame de","count":3},{"next":"strolled along under","previous":"surrounding madame de","count":3}]},{"secret_word":"montrouge","clues":[{"next":"is but a","previous":"the fortifications of","count":3},{"next":"to get the","previous":"of going to","count":3},{"next":"for the night","previous":"to go to","count":3},{"next":"by the same","previous":"little house at","count":3},{"next":"house and there","previous":"more than the","count":3},{"next":"at the gates","previous":"me up at","count":3},{"next":"omnibus bore away","previous":"midnight the last","count":3},{"next":"or elsewhere and","previous":"quarter at belleville","count":3},{"next":"adjoined the one","previous":"planus lived at","count":3},{"next":"to his cottage","previous":"he retired to","count":1},{"next":"where they had","previous":"my boots from","count":1},{"next":"on the previous","previous":"aunt s at","count":1},{"next":"qui cassait le","previous":"petit picier de","count":1}]},{"secret_word":"mouillard","clues":[{"next":"you will be","previous":"in visiting monsieur","count":3},{"next":"was up at","previous":"years since monsieur","count":3},{"next":"as is only","previous":"to you monsieur","count":3},{"next":"and as my","previous":"to modesty monsieur","count":3},{"next":"who am chiefly","previous":"is i monsieur","count":3},{"next":"your nephew your","previous":"come come monsieur","count":3},{"next":"broke in the","previous":"my dear monsieur","count":3},{"next":"up to bed","previous":"better take monsieur","count":3},{"next":"you would see","previous":"our eyes monsieur","count":3},{"next":"that we shall","previous":"nine tell monsieur","count":3},{"next":"looking through them","previous":"cataloguing books monsieur","count":3}]},{"secret_word":"mousko","clues":[{"next":"seated at the","previous":"and a little","count":4},{"next":"on our knees","previous":"the jolly little","count":4},{"next":"home to his","previous":"must carry the","count":4},{"next":"on my back","previous":"shape of a","count":4},{"next":"is the masculine","previous":"this little mousko","count":3},{"next":"mousko is the","previous":"brought this little","count":3},{"next":"jokingly exclaim what","previous":"me with this","count":3},{"next":"i am carrying","previous":"sight of the","count":3},{"next":"i with her","previous":"brought this little","count":1},{"next":"chaffingly exclaim what","previous":"me with this","count":1},{"next":"i am carrying","previous":"get over the","count":1}]},{"secret_word":"mousme","clues":[{"next":"charmingly dressed a","previous":"a perfectly exquisite","count":3},{"next":"guests and from","previous":"with us several","count":3},{"next":"who may be","previous":"to kiss any","count":3},{"next":"or on my","previous":"part of my","count":3},{"next":"can be doing","previous":"know what my","count":3},{"next":"kikou kikou san","previous":"also call my","count":3},{"next":"appeared a little","previous":"suddenly this little","count":3},{"next":"and curious to","previous":"awake my surprised","count":3},{"next":"an indifference an","previous":"notice in my","count":3},{"next":"there can not","previous":"shall be your","count":3},{"next":"and i went","previous":"today yves my","count":3},{"next":"pricks her fingers","previous":"splits breaks the","count":3}]},{"secret_word":"mousmes","clues":[{"next":"a strange musical","previous":"by those two","count":3},{"next":"climbing up the","previous":"and the two","count":3},{"next":"with the interrupted","previous":"and the smiling","count":3},{"next":"of the neighborhood","previous":"and all the","count":3},{"next":"shut up in","previous":"in them the","count":3},{"next":"has picked up","previous":"in visiting the","count":3},{"next":"come out of","previous":"over and the","count":3},{"next":"tell us with","previous":"own so our","count":3},{"next":"begin to listen","previous":"animated and the","count":3},{"next":"of yellow race","previous":"indefinable odor of","count":3},{"next":"and the burning","previous":"respiration of the","count":3},{"next":"rise to depart","previous":"sashes and the","count":3},{"next":"to watch your","previous":"touki all your","count":3}]},{"secret_word":"nagasaki","clues":[{"next":"above all very","previous":"a thing in","count":4},{"next":"i had engaged","previous":"in renown in","count":4},{"next":"appeared to me","previous":"old town of","count":4},{"next":"to be taken","previous":"best photographer in","count":4},{"next":"is spread out","previous":"beyond behind them","count":4},{"next":"is at this","previous":"yesterday and all","count":4},{"next":"illumined by moonlight","previous":"immense blue background","count":4},{"next":"in the most","previous":"farthest end of","count":4},{"next":"mesdemoiselles purete orange","previous":"in vogue in","count":3},{"next":"tonight but like","previous":"go down into","count":3},{"next":"arises a sudden","previous":"depths below in","count":3},{"next":"about five or","previous":"fine town of","count":3},{"next":"in the hope","previous":"a steamer at","count":1}]},{"secret_word":"nailles","clues":[{"next":"has the honor","previous":"the baroness de","count":3},{"next":"have long ceased","previous":"of mademoiselle de","count":3},{"next":"having come back","previous":"this madame de","count":3},{"next":"was far from","previous":"to mademoiselle de","count":3},{"next":"had been once","previous":"another jacqueline de","count":3},{"next":"was fanciful and","previous":"that mademoiselle de","count":3},{"next":"has not just","previous":"that mademoiselle de","count":3},{"next":"and authorizing me","previous":"on mademoiselle de","count":3},{"next":"was sent for","previous":"said mademoiselle de","count":3},{"next":"a few days","previous":"keep mademoiselle de","count":3},{"next":"all the summer","previous":"keeping mademoiselle de","count":3},{"next":"her stepdaughter to","previous":"mademoiselle jacqueline de","count":3}]},{"secret_word":"nointel","clues":[{"next":"whose influence was","previous":"and madame de","count":3},{"next":"did not escape","previous":"and madame de","count":3},{"next":"and madame thomery","previous":"the vicomtesse de","count":3},{"next":"is a tax","previous":"the vicomtesse de","count":3},{"next":"let him sit","previous":"of madame de","count":3},{"next":"said with some","previous":"him madame de","count":3},{"next":"of the circle","previous":"asked madame de","count":3},{"next":"with a burst","previous":"added madame de","count":3},{"next":"to her neighbor","previous":"whispered madame de","count":3},{"next":"behind the shelter","previous":"whispered madame de","count":3},{"next":"has wittily named","previous":"circumstance madame de","count":3},{"next":"with the general","previous":"nointel madame de","count":3}]},{"secret_word":"notre","clues":[{"next":"dame des champs","previous":"in the rue","count":15},{"next":"dame des champs","previous":"to the rue","count":4},{"next":"vie est peu","previous":"cher maupertuis que","count":2},{"next":"dame madame in","previous":"the neighbourhood of","count":1},{"next":"brillante capitale o","previous":"on may 'dans","count":1},{"next":"dame was booming","previous":"great bell of","count":1},{"next":"dame des champs","previous":"along the rue","count":1},{"next":"dame des champs","previous":"six bis rue","count":1},{"next":"dame de champs","previous":"s flat in","count":1},{"next":"ame c'est cet","previous":"se plait d'entretenir","count":1},{"next":"dame de carmel","previous":"esprit saint michel","count":1},{"next":"amiti nous ne","previous":"seul qui produit","count":1},{"next":"sang nous m","previous":"indiff rence serait","count":1}]},{"secret_word":"nougarede","clues":[{"next":"expects as madame","previous":"the result monsieur","count":3},{"next":"had given him","previous":"the reasons that","count":3},{"next":"had summoned the","previous":"of madame dammauville","count":3},{"next":"asked him to","previous":"when phillis and","count":3},{"next":"of an affection","previous":"to phillis and","count":3},{"next":"was nothing to","previous":"or disappointment of","count":3},{"next":"should find a","previous":"room and that","count":3},{"next":"and of all","previous":"madame cormier and","count":3},{"next":"he repeated to","previous":"phillis and to","count":3},{"next":"florentin himself whom","previous":"phillis madame cormier","count":3},{"next":"but for himself","previous":"theatre' prepared by","count":2}]},{"secret_word":"nucingen","clues":[{"next":"the middle classes","previous":"the firm of","count":9},{"next":"father goriot pierrette","previous":"the firm of","count":8},{"next":"cousin betty the","previous":"the firm of","count":7},{"next":"a man of","previous":"the firm of","count":6},{"next":"the peasantry blondet","previous":"the firm of","count":4},{"next":"and the marquis","previous":"the baron de","count":2},{"next":"with a wave","previous":"to monsieur de","count":2},{"next":"the dish covers","previous":"showing monsieur de","count":2},{"next":"baron frederic de","previous":"princess cousin betty","count":2},{"next":"and gamble on","previous":"tillet or a","count":2},{"next":"and several less","previous":"la maison de","count":1},{"next":"for la presse","previous":"la maison de","count":1},{"next":"gaudissart felix scenes","previous":"the firm of","count":1}]},{"secret_word":"occur","clues":[{"next":"to him that","previous":"it did not","count":68},{"next":"to me to","previous":"it did not","count":12},{"next":"to him that","previous":"it would never","count":3},{"next":"to him that","previous":"never seems to","count":2},{"next":"the knights of","previous":"this should not","count":1},{"next":"that might win","previous":"an adventure might","count":1},{"next":"to her at","previous":"time did not","count":1},{"next":"to lothario that","previous":"it did not","count":1},{"next":"to me you","previous":"if any accident","count":1},{"next":"so going up","previous":"further misadventure could","count":1},{"next":"to us youth","previous":"circumstances which occasionally","count":1},{"next":"in it and","previous":"translations or mistranslations","count":1}]},{"secret_word":"online","clues":[{"next":"distributed proofreading team","previous":"franks and the","count":134},{"next":"distributed proofreading team","previous":"the project gutenberg","count":114},{"next":"distributed proofreading team","previous":"frank and the","count":41},{"next":"distributed proofreading team","previous":"meehan and the","count":31},{"next":"distributed proofreading team","previous":"and the pg","count":18},{"next":"distributed proofreading team","previous":"produced by the","count":6},{"next":"distributed proofreading team","previous":"garcia and the","count":6},{"next":"distributed proofreading team","previous":"aldarondo and the","count":6},{"next":"distributed proofreading team","previous":"weyant and the","count":5},{"next":"distributed proofreading team","previous":"connal and the","count":4},{"next":"distributed proofreading team","previous":"berger and the","count":3},{"next":"distributed proofreading team","previous":"widger and the","count":3},{"next":"distributed proofreading team","previous":"the project gutenbert","count":2},{"next":"distributed proofreading team","previous":"vergon and the","count":2},{"next":"distributed proofreaders boswell's","previous":"king and the","count":1},{"next":"distributed proofreading team","previous":"moynihan and the","count":1},{"next":"distributed proofreading team","previous":"agren and the","count":1},{"next":"distributed proofreading team","previous":"d'hooghe and the","count":1},{"next":"distributed proofreading team","previous":"ehler and the","count":1}]},{"secret_word":"oyouki","clues":[{"next":"san madame touki","previous":"while her friends","count":4},{"next":"and mademoiselle dede","previous":"are grouped chrysantheme","count":3},{"next":"very taking in","previous":"first comes mademoiselle","count":3},{"next":"some romance slow","previous":"she often teaches","count":3},{"next":"and myself have","previous":"we yves chrysantheme","count":3},{"next":"bursts into our","previous":"moment after mademoiselle","count":3},{"next":"pretty little physiognomies","previous":"silver topknots like","count":3},{"next":"and i in","previous":"town yves chrysantheme","count":3},{"next":"san and mademoiselle","previous":"mademoiselle la neige","count":3},{"next":"or their young","previous":"prune or mademoiselle","count":3},{"next":"with me i","previous":"yves with chrysantheme","count":3},{"next":"with me fraise","previous":"chrysantheme with yves","count":3}]},{"secret_word":"pagodas","clues":[{"next":"which at certain","previous":"and its great","count":4},{"next":"of which the","previous":"of the thousand","count":4},{"next":"its mountains its","previous":"all nagasaki its","count":4},{"next":"where the other","previous":"trees and gloomy","count":4},{"next":"situated in the","previous":"seals for inferior","count":4},{"next":"and mountains i","previous":"marvellous panorama of","count":3},{"next":"down with the","previous":"down with the","count":2},{"next":"of ganjam jeremy","previous":"the three juggernaut","count":1},{"next":"and green dragons","previous":"of mandarins and","count":1},{"next":"or swiss cottages","previous":"water no chinese","count":1},{"next":"were bright and","previous":"chinese dragons and","count":1},{"next":"and the brahmins","previous":"priests in the","count":1}]},{"secret_word":"panine","clues":[{"next":"and not that","previous":"the name of","count":3},{"next":"were just coming","previous":"prince and princess","count":3},{"next":"eager to find","previous":"in short said","count":3},{"next":"what do you","previous":"well then cried","count":3},{"next":"making the young","previous":"am ungrateful interrupted","count":3},{"next":"who was no","previous":"mistress to enlighten","count":3},{"next":"who was at","previous":"sought to save","count":3},{"next":"sadly and believe","previous":"yes madame answered","count":3},{"next":"simply saying read","previous":"handed it to","count":3},{"next":"if the shareholders","previous":"fraud without implicating","count":3},{"next":"a man weeps","previous":"the entire serge","count":1},{"next":"if he looked","previous":"again to serge","count":1}]},{"secret_word":"papillon","clues":[{"next":"is the inevitable","previous":"by turns arthur","count":3},{"next":"pointed out to","previous":"by pere issacar","count":3},{"next":"seated at one","previous":"the lycee arthur","count":3},{"next":"like a frail","previous":"he followed arthur","count":3},{"next":"who paves the","previous":"that day arthur","count":3},{"next":"the distinguished latin","previous":"it is arthur","count":3},{"next":"pointed out to","previous":"these notabilities whom","count":3},{"next":"on the subject","previous":"not attacked arthur","count":3},{"next":"stopped before the","previous":"seated beside arthur","count":3},{"next":"a pedant and","previous":"genuine idiot arthur","count":3},{"next":"who gave him","previous":"carriage with arthur","count":3},{"next":"and so on","previous":"over swimming en","count":2},{"next":"and been very","previous":"dusantoy and miss","count":1}]},{"secret_word":"parva","clues":[{"next":"of the adi","previous":"in the astika","count":24},{"next":"seges satis est","previous":"of this kind","count":2},{"next":"of the sabha","previous":"in the rajasuyika","count":1},{"next":"sed apta mihi","previous":"over ariosto's door","count":1},{"next":"naturalia by w","previous":"de anima with","count":1},{"next":"in the wye","previous":"building at tintern","count":1},{"next":"vaisampayana said beholding","previous":"xxxix sisupala badha","count":1},{"next":"naturaha greek and","previous":"fallacies e poste","count":1},{"next":"vaisampayana said in","previous":"section xxxii rajasuyika","count":1},{"next":"vaisampayana said on","previous":"section xxxv arghyaharana","count":1},{"next":"vaisampayana said when","previous":"section xlv dyuta","count":1},{"next":"in the delta","previous":"behutet or diospolis","count":1}]},{"secret_word":"peppino","clues":[{"next":"ardea words almost","previous":"by saying to","count":3},{"next":"ardea and fanny","previous":"in honor of","count":3},{"next":"ardea i know","previous":"in saying to","count":3},{"next":"that poor alba","previous":"her conversation with","count":3},{"next":"ardea well i","previous":"she said to","count":3},{"next":"countess added he","previous":"leave you to","count":3},{"next":"ardea who will","previous":"i was with","count":3},{"next":"ardea laughing i","previous":"believe me replied","count":3},{"next":"shaking his head","previous":"ah contessina replied","count":3},{"next":"is not worthy","previous":"embraced her saying","count":3},{"next":"said to himself","previous":"cross street while","count":3},{"next":"was were on","previous":"salon in which","count":3}]},{"secret_word":"pernot","clues":[{"next":"weighed heavily upon","previous":"by the abbe","count":3},{"next":"the curate of","previous":"of the abbe","count":3},{"next":"had made up","previous":"of the abbe","count":3},{"next":"himself were made","previous":"to the abbe","count":3},{"next":"and leaning toward","previous":"from the abbe","count":3},{"next":"was walking as","previous":"true the abbe","count":3},{"next":"seated on a","previous":"found the abbe","count":3},{"next":"making a slight","previous":"replied the abbe","count":3},{"next":"who was striding","previous":"across the abbe","count":3},{"next":"inquiringly rolling his","previous":"repeated the abby","count":3},{"next":"flinging to one","previous":"claudet the abbe","count":3}]},{"secret_word":"pierrepont","clues":[{"next":"at the union","previous":"to his son","count":14},{"next":"at harvard university","previous":"to his son","count":6},{"next":"at the scrub","previous":"to his son","count":2},{"next":"afterwards lady mary","previous":"of lady mary","count":1},{"next":"eldest daughter of","previous":"famous lady mary","count":1},{"next":"well i'm headed","previous":"london october dear","count":1},{"next":"yours of the","previous":"london october dear","count":1},{"next":"who is this","previous":"york november dear","count":1},{"next":"if that's what","previous":"boston november dear","count":1},{"next":"i met young","previous":"chicago july dear","count":1},{"next":"i judge from","previous":"chicago september dear","count":1},{"next":"if you happen","previous":"karlsbad october dear","count":1}]},{"secret_word":"pierrette","clues":[{"next":"a study of","previous":"the government clerks","count":11},{"next":"cesar birotteau lost","previous":"nucingen father goriot","count":8},{"next":"melmoth reconciled a","previous":"the middle classes","count":1},{"next":"the seamy side","previous":"the government clerks","count":1},{"next":"lay and went","previous":"the grave where","count":1},{"next":"daily doctor martener","previous":"men think of","count":1},{"next":"quite pretty but","previous":"a girl named","count":1},{"next":"for her journey","previous":"he had given","count":1},{"next":"in her grave","previous":"which laid our","count":1},{"next":"concealed the effects","previous":"is proved that","count":1},{"next":"made him a","previous":"last offices for","count":1},{"next":"the vendetta rouget","previous":"birotteau eugenie grandet","count":1},{"next":"and le cure","previous":"vallee l'illustre gaudissart","count":1}]},{"secret_word":"pietrapertosa","clues":[{"next":"and after her","previous":"of old duchess","count":3},{"next":"when that snob","previous":"of casal interrupted","count":3},{"next":"sententiously one should","previous":"a duel continued","count":3},{"next":"making with his","previous":"was there replied","count":3},{"next":"and cibo who","previous":"he came upon","count":3},{"next":"and the doctor","previous":"had brought cibo","count":3},{"next":"hafner ardea try","previous":"vain did cibo","count":3},{"next":"who did not","previous":"addressing cibo and","count":3},{"next":"and that the","previous":"cibo and of","count":3},{"next":"would have consented","previous":"cibo and that","count":3},{"next":"such preliminaries are","previous":"montfanon cibo and","count":3},{"next":"heedless of cibo's","previous":"her husband said","count":2},{"next":"heedless of cibo","previous":"her husband said","count":1}]},{"secret_word":"planus","clues":[{"next":"had the greatest","previous":"and yet sigismond","count":3},{"next":"came to say","previous":"that moment mademoiselle","count":3},{"next":"entered the room","previous":"that moment mademoiselle","count":3},{"next":"ventured to say","previous":"after all mademoiselle","count":3},{"next":"a melancholy outlook","previous":"so vaunted by","count":3},{"next":"recognize risler aine","previous":"then did mademoiselle","count":3},{"next":"my brother risler","previous":"know beside monsieur","count":3},{"next":"as he dressed","previous":"sister said poor","count":3},{"next":"had no great","previous":"reached that point","count":3},{"next":"was sitting in","previous":"removed untouched mademoiselle","count":3},{"next":"and began to","previous":"everybody looked at","count":3},{"next":"went up to","previous":"garden door mademoiselle","count":3}]},{"secret_word":"plastramengro","clues":[{"next":"went to the","previous":"full moon the","count":3},{"next":"from behind the","previous":"out bolted the","count":3},{"next":"held on like","previous":"not do the","count":3},{"next":"thought of himself","previous":"know what the","count":3},{"next":"which if it","previous":"blow at the","count":3},{"next":"placed himself behind","previous":"brother where the","count":3},{"next":"pulled out his","previous":"lane and the","count":3},{"next":"would never have","previous":"rommany chal the","count":3},{"next":"from bow street","previous":"sent for a","count":2},{"next":"placed himself in","previous":"trees so the","count":2},{"next":"waited behind the","previous":"risen and the","count":2},{"next":"notwithstanding he went","previous":"brother that the","count":2},{"next":"waited behind a","previous":"risen and the","count":1}]},{"secret_word":"plumet","clues":[{"next":"told her you","previous":"her portrait madame","count":3},{"next":"about packing it","previous":"just arranged with","count":3},{"next":"who is sure","previous":"go to madame","count":3},{"next":"who leaned motionless","previous":"turning to madame","count":3},{"next":"to tell me","previous":"shall ask monsieur","count":3},{"next":"in person who","previous":"details from madame","count":3},{"next":"to tell me","previous":"note from madame","count":3},{"next":"unknown to all","previous":"arranged by madame","count":3},{"next":"have locked up","previous":"monsieur and madame","count":3},{"next":"broke in 'excuse","previous":"grasp it madame","count":2},{"next":"he saw a","previous":"the rue de","count":1}]},{"secret_word":"pointers","clues":[{"next":"at the end","previous":"of bookmarks or","count":57},{"next":"during that week","previous":"the older west","count":1},{"next":"had once yapped","previous":"which the colonel's","count":1},{"next":"over the head","previous":"one of my","count":1},{"next":"are useless for","previous":"my north carolina","count":1},{"next":"are not yet","previous":"my poney and","count":1},{"next":"were visible in","previous":"nor the two","count":1},{"next":"as to put","previous":"given me such","count":1},{"next":"might have afforded","previous":"horses greyhounds and","count":1},{"next":"responded the sitter","previous":"chance to get","count":1},{"next":"lying under a","previous":"fiercest of the","count":1},{"next":"and so forth","previous":"artists' colourmen models","count":1}]},{"secret_word":"prerolles","clues":[{"next":"went to visit","previous":"and henri de","count":3},{"next":"it had become","previous":"the lords of","count":3},{"next":"hardly more than","previous":"the tower of","count":3},{"next":"was inscribed in","previous":"the marquis de","count":3},{"next":"in full uniform","previous":"the marquis de","count":3},{"next":"your glorious career","previous":"the marquis de","count":3},{"next":"the next day","previous":"the marquise de","count":3},{"next":"assume this responsibility","previous":"the marquise de","count":3},{"next":"who at that","previous":"asked general de","count":3},{"next":"realized her ideal","previous":"like general de","count":3},{"next":"said the military","previous":"yourself general de","count":3},{"next":"sustained by a","previous":"solicitude henri de","count":3}]},{"secret_word":"prevention","clues":[{"next":"of cruelty to","previous":"society for the","count":20},{"next":"of cruelty to","previous":"bill for the","count":2},{"next":"bill by the","previous":"opposing the cruelty","count":2},{"next":"into holy orders","previous":"all possibility of","count":1},{"next":"though base yet","previous":"him upon a","count":1},{"next":"i shall have","previous":"which without some","count":1},{"next":"of spinsterhood to","previous":"society for the","count":1},{"next":"rather than cure","previous":"be that of","count":1},{"next":"of the same","previous":"before yudhishthira the","count":1},{"next":"of much misery","previous":"providence for the","count":1},{"next":"of your ruin","previous":"authority for the","count":1},{"next":"of capital punishment","previous":"abstinence and the","count":1}]},{"secret_word":"priced","clues":[{"next":"editions re issues","previous":"books in popular","count":21},{"next":"at one shilling","previous":"and might be","count":2},{"next":"at fifty francs","previous":"for gavarnie was","count":2},{"next":"which is of","previous":"the original option","count":1},{"next":"sketches in vaudeville","previous":"of the highest","count":1},{"next":"tenants they enjoyed","previous":"from its highest","count":1},{"next":"rooms with or","previous":"were offered low","count":1},{"next":"articles of everyday","previous":"were instituted low","count":1},{"next":"them a hundred","previous":"them over and","count":1},{"next":"place to live","previous":"want a medium","count":1},{"next":"duties per quarter","previous":"grain at various","count":1},{"next":"and placed house","previous":"send word what","count":1},{"next":"medicines of which","previous":"buy some high","count":1}]},{"secret_word":"project","clues":[{"next":"gutenberg online distributed","previous":"meehan and the","count":18},{"next":"gutenberg edition to","previous":"in the present","count":1},{"next":"applauded his crazy","previous":"with his new","count":1},{"next":"but mine cruel","previous":"out his vile","count":1},{"next":"that of a","previous":"been a favourite","count":1},{"next":"gutenberg in text","previous":"also available from","count":1},{"next":"may appear it","previous":"wild as the","count":1},{"next":"to limit six","previous":"thy horns to","count":1},{"next":"of the duke","previous":"greatly aided the","count":1},{"next":"of removing the","previous":"connected with his","count":1},{"next":"gutenberg distributed proofreaders","previous":"richard prairie and","count":1},{"next":"ready prepared and","previous":"gemma with a","count":1},{"next":"gutenberg online distributed","previous":"maddock and the","count":1}]},{"secret_word":"proofreading","clues":[{"next":"team at http","previous":"the online distributed","count":209},{"next":"team at https","previous":"the online distributed","count":134},{"next":"team https www","previous":"gutenberg online distributed","count":58},{"next":"team http www","previous":"gutenberg online distributed","count":32},{"next":"team html file","previous":"and the distributed","count":1},{"next":"team the story","previous":"the online distributed","count":1},{"next":"team the works","previous":"the online distributed","count":1},{"next":"team the living","previous":"the online distributed","count":1},{"next":"team the abbot's","previous":"the online distributed","count":1},{"next":"team behind a","previous":"the online distributed","count":1},{"next":"team love at","previous":"gutenberg online distributed","count":1},{"next":"team love's shadow","previous":"gutenberg online distributed","count":1},{"next":"team bertha garlan","previous":"gutenberg online distributed","count":1},{"next":"team viviette by","previous":"gutenberg online distributed","count":1},{"next":"team the life","previous":"gutenbert online distributed","count":1}]},{"secret_word":"rameures","clues":[{"next":"or his niece","previous":"the terrible des","count":3},{"next":"but the old","previous":"of the des","count":3},{"next":"may i have","previous":"of monsieur des","count":3},{"next":"frequently occurred in","previous":"name of des","count":3},{"next":"lives much farther","previous":"woman monsieur des","count":3},{"next":"which gives an","previous":"her uncle des","count":3},{"next":"notwithstanding the tender","previous":"their uncle des","count":3},{"next":"is the master","previous":"them for des","count":3},{"next":"but paris is","previous":"my uncle des","count":3},{"next":"and his niece","previous":"those of des","count":3},{"next":"will not hear","previous":"those of des","count":3}]},{"secret_word":"reason","clues":[{"next":"why he should","previous":"there was no","count":53},{"next":"for prompt action","previous":"all the more","count":1},{"next":"about so lucidly","previous":"all he could","count":1},{"next":"and the flow","previous":"this feast of","count":1},{"next":"less a favourite","previous":"was for some","count":1},{"next":"as i can","previous":"there ain't any","count":1},{"next":"a new reason","previous":"you yet the","count":1},{"next":"finished shepler who","previous":"something superior to","count":1},{"next":"why you must","previous":"reason a new","count":1},{"next":"why new york","previous":"us that's no","count":1},{"next":"for descending upon","previous":"uncle peter's true","count":1},{"next":"why you can't","previous":"ain't really any","count":1},{"next":"that the father","previous":"alternative for the","count":1}]},{"secret_word":"redingote","clues":[{"next":"was seated on","previous":"of his black","count":3},{"next":"trimmed with braid","previous":"a long travelling","count":3},{"next":"exhibited a face","previous":"a somewhat shabby","count":3},{"next":"departed regularly every","previous":"in a black","count":3},{"next":"with military buttons","previous":"in his long","count":3},{"next":"and balancing with","previous":"in his travelling","count":3},{"next":"on the buttons","previous":"with his long","count":3},{"next":"the waiting cavalier","previous":"pockets in his","count":3},{"next":"and put on","previous":"buttoned up his","count":3},{"next":"type trimmed with","previous":"of the antiquated","count":1},{"next":"my black trousers","previous":"with my maroon","count":1},{"next":"and loose byron","previous":"light kerseymere breeches","count":1},{"next":"and holding his","previous":"clad in his","count":1}]},{"secret_word":"reign","clues":[{"next":"of george iii","previous":"journal of the","count":36},{"next":"of george iii","previous":"memoirs of the","count":26},{"next":"in the spring","previous":"that during my","count":2},{"next":"in one of","previous":"certainly ceased to","count":2},{"next":"and recover his","previous":"to return to","count":1},{"next":"with science dignifies","previous":"were renown'd whose","count":1},{"next":"to quit she","previous":"length her ancient","count":1},{"next":"translated royal anne","previous":"mortal to immortal","count":1},{"next":"but distant be","previous":"blissful isles to","count":1},{"next":"to all eternity","previous":"ceasing may they","count":1},{"next":"of alfonso vii","previous":"moors in the","count":1},{"next":"of nebuchadnezzar i","previous":"zodiac in the","count":1},{"next":"of that fortuitous","previous":"fabricated in the","count":1}]},{"secret_word":"resurrection","clues":[{"next":"and the life","previous":"i am the","count":26},{"next":"through thoth and","previous":"and of his","count":1},{"next":"of osiris were","previous":"the sufferings and","count":1},{"next":"ascension or atonement","previous":"in no historical","count":1},{"next":"in a corner","previous":"who await the","count":1},{"next":"of altisidora though","previous":"proved by the","count":1},{"next":"of the just","previous":"man and the","count":1},{"next":"of this damsel","previous":"do with the","count":1},{"next":"man of science","previous":"fame trumpets this","count":1},{"next":"of the just","previous":"partake of the","count":1},{"next":"and numerous texts","previous":"persecution murder and","count":1},{"next":"and real fireworks","previous":"crucifixion with the","count":1}]},{"secret_word":"reuilly","clues":[{"next":"was several miles","previous":"the station at","count":3},{"next":"at the close","previous":"the woods of","count":3},{"next":"accompanied by the","previous":"the marquise visited","count":3},{"next":"the chateau on","previous":"his estate at","count":3},{"next":"when his first","previous":"his arrival at","count":3},{"next":"as was his","previous":"he remained at","count":3},{"next":"only once during","previous":"he went to","count":3},{"next":"since her husband","previous":"to live at","count":3},{"next":"the preceding week","previous":"had gone to","count":3},{"next":"and make of","previous":"your wand over","count":3},{"next":"during the summer","previous":"kept him at","count":3},{"next":"if he wished","previous":"immediately required at","count":3},{"next":"remarking in the","previous":"eight days at","count":3}]},{"secret_word":"ribalta","clues":[{"next":"wrapping up his","previous":"the better said","count":3},{"next":"growing more and","previous":"for four insisted","count":3},{"next":"the latter told","previous":"returned it to","count":3},{"next":"had bought the","previous":"to know that","count":3},{"next":"made up his","previous":"greatest care while","count":3},{"next":"who leaping over","previous":"it is said","count":3},{"next":"replied with a","previous":"your inspiration comfortably","count":3},{"next":"arrested tried and","previous":"would undoubtedly have","count":3},{"next":"to morrow and","previous":"anarchist of a","count":3},{"next":"who is ending","previous":"revolutionists like boorish","count":3},{"next":"s in time","previous":"haste to reach","count":1}]},{"secret_word":"roger's","clues":[{"next":"friends are afraid","previous":"some of sir","count":4},{"next":"party has it","previous":"not of sir","count":4},{"next":"servants would ride","previous":"one of sir","count":3},{"next":"dinner almost cold","previous":"my friend sir","count":3},{"next":"upon the coming","previous":"custom at sir","count":3},{"next":"may have created","previous":"enjoy at sir","count":3},{"next":"in the country","previous":"stay at sir","count":3},{"next":"alighting told him","previous":"keeper upon sir","count":3},{"next":"who pretended to","previous":"said of sir","count":2},{"next":"charge are the","previous":"merry on sir","count":2},{"next":"chaplain but actually","previous":"counsellor than sir","count":2},{"next":"false nattering tongue","previous":"deluded away by","count":1}]},{"secret_word":"rommany","clues":[{"next":"chal shall jaw","previous":"chi and the","count":6},{"next":"churl and the","previous":"and sang the","count":4},{"next":"girl to morrow","previous":"churl and the","count":4},{"next":"chal i should","previous":"and become a","count":3},{"next":"chi ' none","previous":"the drom miro","count":3},{"next":"chal after he","previous":"why brother the","count":3},{"next":"chies young fellow","previous":"none of your","count":3},{"next":"chal the plastramengro","previous":"favour of the","count":3},{"next":"chal to escape","previous":"so that the","count":2},{"next":"churl and the","previous":"the gillie the","count":1},{"next":"instead of roman","previous":"is somewhat different","count":1},{"next":"girl love thieving","previous":"churl and the","count":1}]},{"secret_word":"rousselet","clues":[{"next":"he understands all","previous":"and send for","count":3},{"next":"backed out of","previous":"to be repeated","count":3},{"next":"turning to lambernier","previous":"as that observed","count":3},{"next":"that it was","previous":"as well as","count":3},{"next":"more politic than","previous":"themselves as to","count":3},{"next":"is well known","previous":"you madame leonard","count":3},{"next":"said mademoiselle de","previous":"needed no longer","count":3},{"next":"has nothing to","previous":"coachman first that","count":3},{"next":"and that old","previous":"idiot of a","count":3},{"next":"advanced stretching his","previous":"hostilities had begun","count":3}]},{"secret_word":"sam'l","clues":[{"next":"had treated bell","previous":"in thrums that","count":3},{"next":"superintend the fitting","previous":"delicacy that made","count":3},{"next":"dickie trying to","previous":"i remember seeing","count":3},{"next":"would reply but","previous":"i d'na kin","count":3},{"next":"and sanders at","previous":"then praying for","count":3},{"next":"he's a mairit","previous":"gran' prayers but","count":3},{"next":"said sanders soothingly","previous":"a' oor troubles","count":3},{"next":"no to be","previous":"warnin' to ye","count":3},{"next":"in a voice","previous":"sanders sanders said","count":3},{"next":"bending forward and","previous":"sanders laddie said","count":3},{"next":"wilkie respectively a","previous":"silva mcqueen and","count":2},{"next":"todd by himself","previous":"afterward told of","count":1}]},{"secret_word":"sample","clues":[{"next":"the author's ideas","previous":"may wish to","count":57},{"next":"of personal attributes","previous":"by a faultless","count":1},{"next":"room that nothing","previous":"the bigelow house","count":1},{"next":"of beauty and","previous":"was a striking","count":1},{"next":"as soon as","previous":"he gave a","count":1},{"next":"case beside the","previous":"he dropped his","count":1},{"next":"rooms in the","previous":"as against two","count":1},{"next":"of to begin","previous":"have given a","count":1},{"next":"of the two","previous":"we offer a","count":1},{"next":"of my hand","previous":"merely as a","count":1},{"next":"packages of fine","previous":"discreetly at the","count":1},{"next":"of folks said","previous":"masons a curious","count":1}]},{"secret_word":"saniel","clues":[{"next":"accepted all his","previous":"and fetes and","count":3},{"next":"for it manifested","previous":"the change from","count":3},{"next":"had made did","previous":"the connections that","count":3},{"next":"with outstretched hands","previous":"he came to","count":3},{"next":"has originality and","previous":"no chance friend","count":3},{"next":"did not return","previous":"after long years","count":3},{"next":"entered her room","previous":"she was dressing","count":3},{"next":"tried to transform","previous":"she slept that","count":3},{"next":"they were too","previous":"did not please","count":3},{"next":"had felt since","previous":"relative calm that","count":3},{"next":"taking off his","previous":"outstretched hands and","count":3},{"next":"for whom he","previous":"facial neuralgia by","count":3}]},{"secret_word":"savigny","clues":[{"next":"in the vast","previous":"the road to","count":3},{"next":"by the lyon","previous":"to connect with","count":3},{"next":"watched her approach","previous":"to het that","count":3},{"next":"is open to","previous":"one is that","count":3},{"next":"and that i","previous":"things down at","count":3},{"next":"tomorrow and ask","previous":"will go to","count":3},{"next":"in the evening","previous":"sometimes too at","count":3},{"next":"seemed to say","previous":"tightly closed exterior","count":3},{"next":"no matter where","previous":"orleans perhaps to","count":3},{"next":"did for the","previous":"the mollusca what","count":1},{"next":"had to arrive","previous":"i berthe de","count":1},{"next":"delaunay who was","previous":"blanche croizette kissing","count":1}]},{"secret_word":"savinien","clues":[{"next":"rushed forward and","previous":"his aunt enter","count":3},{"next":"and with an","previous":"is here replied","count":3},{"next":"who abashed went","previous":"hand she dismissed","count":3},{"next":"quickly i wish","previous":"my income interrupted","count":3},{"next":"with an indignant","previous":"i want said","count":3},{"next":"followed by marechal","previous":"heard approaching and","count":3},{"next":"and said by","previous":"mistress turned to","count":3},{"next":"like two aides","previous":"stood marechal and","count":3},{"next":"herzog and his","previous":"carriages bearing away","count":3},{"next":"that i a","previous":"idiots marechal sighed","count":3},{"next":"were opened and","previous":"herzog marechal and","count":3},{"next":"de portenduere who","previous":"like his companion","count":1}]},{"secret_word":"schult","clues":[{"next":"having told her","previous":"for goethe fraulein","count":3},{"next":"was false to","previous":"cause that fraulein","count":3},{"next":"and jacqueline to","previous":"habit with fraulein","count":3},{"next":"who was still","previous":"back to fraulein","count":3},{"next":"who was not","previous":"amusement of fraulein","count":3},{"next":"who had known","previous":"intercourse with fraulein","count":3},{"next":"moved much as","previous":"confided to fraulein","count":3},{"next":"who was at","previous":"glanced at fraulein","count":3},{"next":"after listening day","previous":"surprising that fraulein","count":3},{"next":"were well calculated","previous":"propriety of fraulein","count":3},{"next":"who perfidiously day","previous":"wretchedness to fraulein","count":3},{"next":"to imagine something","previous":"jacqueline begged fraulein","count":3}]},{"secret_word":"sciences","clues":[{"next":"morales et politiques","previous":"de l'academie des","count":25},{"next":"have you studied","previous":"the schools what","count":1},{"next":"you must descend","previous":"of the high","count":1},{"next":"especially that one","previous":"of all the","count":1},{"next":"and other knowledge","previous":"was like other","count":1},{"next":"i found him","previous":"study of other","count":1},{"next":"in the world","previous":"most of the","count":1},{"next":"to adorn and","previous":"other languages or","count":1},{"next":"laboriously piecing together","previous":"aid of several","count":1},{"next":"and she must","previous":"rest of the","count":1},{"next":"which is that","previous":"step of the","count":1},{"next":"and took long","previous":"teacher of natural","count":1},{"next":"and cut down","previous":"vessel of the","count":1}]},{"secret_word":"scribner's","clues":[{"next":"sons copyright by","previous":"new york charles","count":11},{"next":"sons published march","previous":"copyright by charles","count":5},{"next":"magazine appeared and","previous":"when the new","count":2},{"next":"sons if he","previous":"house of charles","count":2},{"next":"magazine and mr","previous":"decided to start","count":2},{"next":"sons as stenographer","previous":"employ of charles","count":2},{"next":"sons which mr","previous":"advertisements of charles","count":2},{"next":"magazine saw my","previous":"the editors of","count":1},{"next":"and the broken","previous":"of harper's and","count":1},{"next":"monthly which contains","previous":"was published in","count":1},{"next":"under the title","previous":"in the christmas","count":1},{"next":"magazine to write","previous":"present editor of","count":1},{"next":"harper's and the","previous":"sized magazines namely","count":1}]},{"secret_word":"seamy","clues":[{"next":"side of history","previous":"life honorine the","count":11},{"next":"side of history","previous":"the chouans the","count":10},{"next":"side of history","previous":"s establishment the","count":5},{"next":"side of history","previous":"or choisnel the","count":3},{"next":"side of history","previous":"vicomte de the","count":3},{"next":"side of it","previous":"it was the","count":2},{"next":"side without and","previous":"old wits the","count":1},{"next":"side of me","previous":"to see the","count":1},{"next":"side and the","previous":"material has a","count":1},{"next":"side fate attacking","previous":"lady holme its","count":1},{"next":"side of it","previous":"upon her the","count":1},{"next":"sides where none","previous":"i don't invent","count":1},{"next":"kind of thing","previous":"question about that","count":1}]},{"secret_word":"sejournant","clues":[{"next":"volunteer in the","previous":"of germain claudet","count":3},{"next":"prostrate on her","previous":"was intoned manette","count":3},{"next":"replied julien very","previous":"it is claudet","count":3},{"next":"was outlined against","previous":"form of claudet","count":3},{"next":"said he to","previous":"will inform madame","count":3},{"next":"this picturesque expression","previous":"mouth of madame","count":3},{"next":"so powerful that","previous":"affection for young","count":3},{"next":"who is very","previous":"apply to claudet","count":3},{"next":"with her treacherous","previous":"people this manette","count":3},{"next":"the marriage that","previous":"yesterday to claudet","count":3},{"next":"was busy preparing","previous":"kitchen where manette","count":3},{"next":"and her son","previous":"hostility of manette","count":3}]},{"secret_word":"seniavine","clues":[{"next":"general lariviere perhaps","previous":"with us princess","count":3},{"next":"has a fine","previous":"at night princess","count":3},{"next":"at his left","previous":"to the princess","count":3},{"next":"do you ever","previous":"asked the princess","count":3},{"next":"to the buffet","previous":"you escorted princess","count":3},{"next":"this winter asked","previous":"why the princess","count":3},{"next":"who looking superb","previous":"pure cheeks princess","count":3},{"next":"and madame martin","previous":"seat between princess","count":3},{"next":"he added negligently","previous":"berthier or princess","count":3},{"next":"as a page","previous":"schmoll the princess","count":3},{"next":"madame berthier d'eyzelles","previous":"husband the princess","count":2}]},{"secret_word":"side","clues":[{"next":"of the table","previous":"at the other","count":28},{"next":"of the old","previous":"at the other","count":2},{"next":"announcing him on","previous":"name on one","count":1},{"next":"and climbed a","previous":"on the farther","count":1},{"next":"issues he's too","previous":"on those little","count":1},{"next":"as they denominated","previous":"things on this","count":1},{"next":"line of corn","previous":"well take the","count":1},{"next":"of council bluffs","previous":"right the other","count":1},{"next":"allured him with","previous":"woods at either","count":1},{"next":"street where slovenly","previous":"slowly up a","count":1},{"next":"while the driver","previous":"rails on either","count":1},{"next":"' worth speakin'","previous":"wa'n't any 'this","count":1},{"next":"of their stock","previous":"independents know which","count":1}]},{"secret_word":"sigismond","clues":[{"next":"old friend will","previous":"in an undertone","count":3},{"next":"as became an","previous":"his dealings with","count":3},{"next":"she came to","previous":"when she saw","count":3},{"next":"made himself as","previous":"her room and","count":3},{"next":"planus had the","previous":"away and yet","count":3},{"next":"the effect of","previous":"crowd produced upon","count":3},{"next":"who was still","previous":"passed it to","count":3},{"next":"in an undertone","previous":"again and asked","count":3},{"next":"with beaming face","previous":"yourself said honest","count":3},{"next":"planus returned home","previous":"vengeance never had","count":3},{"next":"were drinking their","previous":"stamp risler and","count":3},{"next":"thought he hasn't","previous":"at the bed","count":2}]},{"secret_word":"sillery","clues":[{"next":"with a jeering","previous":"the amiable paul","count":3},{"next":"who breakfasted with","previous":"old friend paul","count":3},{"next":"by the hand","previous":"to take paul","count":3},{"next":"to him as","previous":"it said paul","count":3},{"next":"each would rise","previous":"called upon by","count":3},{"next":"like an apostate","previous":"its decrees paul","count":3},{"next":"who now held","previous":"among others paul","count":3},{"next":"called his name","previous":"fear and when","count":3},{"next":"had talked of","previous":"violette and paul","count":3},{"next":"the call has","previous":"to all from","count":1},{"next":"niece of la","previous":"oise brulart de","count":1},{"next":"soft and creamy","previous":"verzenay and the","count":1}]},{"secret_word":"souvigny","clues":[{"next":"but how sadly","previous":"the pavement of","count":3},{"next":"told us the","previous":"the lawyer from","count":3},{"next":"but cannon ammunition","previous":"the butts at","count":3},{"next":"and when they","previous":"the grisettes of","count":3},{"next":"on the northern","previous":"of longueval near","count":3},{"next":"who was your","previous":"old lawyer in","count":3},{"next":"is necessary it","previous":"but to leave","count":3},{"next":"was three miles","previous":"at souvigny and","count":3},{"next":"while she is","previous":"no more to","count":3},{"next":"for a short","previous":"i must leave","count":3},{"next":"on the th","previous":"will return to","count":3},{"next":"mobiles killed january","previous":"major of the","count":3},{"next":"or the castles","previous":"episcopal palace of","count":3}]},{"secret_word":"steno","clues":[{"next":"was possessed to","previous":"by which madame","count":3},{"next":"aside and saying","previous":"by taking madame","count":3},{"next":"to give an","previous":"of the villa","count":3},{"next":"from connection with","previous":"of exempting madame","count":3},{"next":"as to her","previous":"in consequence mademoiselle","count":3},{"next":"had seated herself","previous":"he when mademoiselle","count":3},{"next":"aided her by","previous":"more easy madame","count":3},{"next":"to rise from","previous":"she forced alba","count":3},{"next":"while lincoln gave","previous":"seated beside madame","count":3},{"next":"that he was","previous":"arriving at villa","count":3},{"next":"in a mournful","previous":"deserves interrupted alba","count":3},{"next":"at six o'clock","previous":"to the villa","count":2},{"next":"in the green","previous":"here the little","count":1}]},{"secret_word":"storks","clues":[{"next":"are playfully disporting","previous":"a few white","count":4},{"next":"is the most","previous":"with flights of","count":4},{"next":"and they all","previous":"with paintings of","count":4},{"next":"but i am","previous":"groups his charming","count":4},{"next":"painted in gray","previous":"group of two","count":4},{"next":"forming a wreath","previous":"inevitable flight of","count":4},{"next":"in a variety","previous":"paint him some","count":4},{"next":"and humorous subjects","previous":"towels decorated with","count":4},{"next":"are similar to","previous":"automatic painters whose","count":4},{"next":"on a pretty","previous":"pair of charming","count":3},{"next":"walk gravely among","previous":"meadows where the","count":1},{"next":"and water lilies","previous":"screens painted with","count":1}]},{"secret_word":"strahlberg","clues":[{"next":"swept away as","previous":"the stage madame","count":3},{"next":"without any reserve","previous":"was praising madame","count":3},{"next":"but that lady","previous":"to rejoin madame","count":3},{"next":"had frightened her","previous":"her by madame","count":3},{"next":"saying that she","previous":"her against madame","count":3},{"next":"kissed her with","previous":"first story madame","count":3},{"next":"of her expulsion","previous":"intimacy with madame","count":3},{"next":"had leaped over","previous":"or rather madame","count":3},{"next":"now absorbed in","previous":"why was madame","count":3},{"next":"was eager for","previous":"excluded for madame","count":3}]},{"secret_word":"sutherland","clues":[{"next":"charles franks and","previous":"produced by juliet","count":13},{"next":"mary meehan and","previous":"produced by juliet","count":6},{"next":"david widger and","previous":"produced by juliet","count":5},{"next":"charles franks and","previous":"andrea ball juliet","count":4},{"next":"thomas berger and","previous":"andrew templeton juliet","count":2},{"next":"charles franks and","previous":"david king juliet","count":2},{"next":"and baring brothers","previous":"the duke of","count":1},{"next":"is described by","previous":"present duchess of","count":1},{"next":"mary meehan david","previous":"produced by juliet","count":1},{"next":"beth trapaga and","previous":"produced by juliet","count":1},{"next":"tonya allen and","previous":"produced by juliet","count":1},{"next":"josephine paolucci tonya","previous":"andrew templeton juliet","count":1},{"next":"and was created","previous":"elizabeth countess of","count":1}]},{"secret_word":"sylvestre","clues":[{"next":"returned and held","previous":"a moment later","count":3},{"next":"did not seem","previous":"following words which","count":3},{"next":"and i owe","previous":"am quite happy","count":3},{"next":"to tell him","previous":"went to see","count":3},{"next":"is defeated for","previous":"broken for good","count":3},{"next":"stuff them away","previous":"hide your sketches","count":3},{"next":"lampron painter in","previous":"sake and mine","count":3},{"next":"no decidedly it","previous":"nice of you","count":3},{"next":"milan june th","previous":"startling news from","count":3},{"next":"lampron's mother the","previous":"dying wish of","count":2},{"next":"it's a customer","previous":"you are said","count":2}]},{"secret_word":"t'nowhead","clues":[{"next":"knew that the","previous":"the servant and","count":3},{"next":"was master in","previous":"a certain point","count":3},{"next":"to mcquhatty and","previous":"his sweetheart ay","count":3},{"next":"on the sabbath","previous":"set off to","count":3},{"next":"had an invitation","previous":"were burning and","count":3},{"next":"pew so well","previous":"them into the","count":3},{"next":"in an hour","previous":"would be at","count":3},{"next":"has wi' her","previous":"what a life","count":3},{"next":"with his feet","previous":"round the fire","count":3},{"next":"he was never","previous":"steep ascent to","count":3},{"next":"was a little","previous":"pig about which","count":3},{"next":"farmer was the","previous":"brother of the","count":2},{"next":"next morning sanders","previous":"the brae to","count":1}]},{"secret_word":"t'nowhead's","clues":[{"next":"bell reached its","previous":"the courting of","count":3},{"next":"wife who liked","previous":"good will of","count":3},{"next":"bell whom he","previous":"thoughts were of","count":3},{"next":"bell and i","previous":"took to wife","count":3},{"next":"litlins an' no","previous":"fell spoilt crew","count":3},{"next":"bell and that","previous":"thinking of courting","count":3},{"next":"bell and her","previous":"fateful sabbath for","count":3},{"next":"bell but it","previous":"the courting of","count":2},{"next":"bell who had","previous":"it happened that","count":2},{"next":"fields the snow","previous":"clear and from","count":2},{"next":"lassie and i","previous":"finger direct at","count":2},{"next":"pew and gavin's","previous":"as gavin passed","count":1}]},{"secret_word":"talbrun","clues":[{"next":"she said the","previous":"for madame de","count":3},{"next":"were aroused the","previous":"an oscar de","count":3},{"next":"seemed to him","previous":"but the name","count":3},{"next":"was in the","previous":"that madame de","count":3},{"next":"was waiting for","previous":"where madame de","count":3},{"next":"turning her head","previous":"said madame de","count":3},{"next":"said the young","previous":"not monsieur de","count":3},{"next":"might also have","previous":"if madame de","count":3},{"next":"to come in","previous":"beg madame de","count":3},{"next":"and tell her","previous":"see madame de","count":3},{"next":"her pale face","previous":"cried madame de","count":3},{"next":"who had secretly","previous":"bigot of a","count":3}]},{"secret_word":"team","clues":[{"next":"at http www","previous":"online distributed proofreading","count":212},{"next":"two hundred miles","previous":"by a mule","count":1},{"next":"all by herself","previous":"a four horse","count":1},{"next":"without any further","previous":"with all his","count":1},{"next":"and it was","previous":"to water his","count":1},{"next":"wound by with","previous":"as a long","count":1},{"next":"and given them","previous":"visit to his","count":1},{"next":"and pursued their","previous":"could loaded their","count":1},{"next":"of cart horses","previous":"crossing where a","count":1},{"next":"of bays that","previous":"slipped under a","count":1},{"next":"for carriage use","previous":"horses and a","count":1},{"next":"bertha garlan by","previous":"online distributed proofreading","count":1}]},{"secret_word":"thuiliere","clues":[{"next":"and spreading an","previous":"sent from la","count":3},{"next":"the grand chasserot","previous":"day at la","count":3},{"next":"in order to","previous":"be at la","count":3},{"next":"and the same","previous":"visit to la","count":3},{"next":"thought she and","previous":"going to la","count":3},{"next":"and soon reached","previous":"direction of la","count":3},{"next":"rose before him","previous":"roofs of la","count":3},{"next":"while the carriage","previous":"road to la","count":3},{"next":"are pouring forth","previous":"garden of la","count":3},{"next":"one june afternoon","previous":"garden of la","count":3},{"next":"the sending of","previous":"belonging to la","count":3},{"next":"the very certainty","previous":"quarters at la","count":3},{"next":"and i don't","previous":"visits to la","count":2}]},{"secret_word":"tour","clues":[{"next":"to the hebrides","previous":"journal of a","count":55},{"next":"was at some","previous":"an extended european","count":1},{"next":"of his clubs","previous":"made a conscientious","count":1},{"next":"de force that","previous":"is a little","count":1},{"next":"of inspection for","previous":"is on a","count":1},{"next":"through france and","previous":"after his professional","count":1},{"next":"four volumes of","previous":"out of this","count":1},{"next":"of inspection over","previous":"been making a","count":1},{"next":"which is so","previous":"you take a","count":1},{"next":"immediately after the","previous":"off on a","count":1},{"next":"of the walls","previous":"making a little","count":1},{"next":"of were paid","previous":"expenses on the","count":1},{"next":"in the private","previous":"latter the leisurely","count":1}]},{"secret_word":"treport","clues":[{"next":"in charge of","previous":"this time at","count":3},{"next":"in a charming","previous":"two miles from","count":3},{"next":"relating a thousand","previous":"first met at","count":3},{"next":"which make stops","previous":"from paris to","count":3},{"next":"very much because","previous":"i should like","count":3},{"next":"on that train","previous":"every saturday to","count":3},{"next":"he led the","previous":"last summer at","count":3},{"next":"except to invoke","previous":"frequently to visit","count":3},{"next":"is he not","previous":"wermant is at","count":3},{"next":"raoul with his","previous":"wermants came to","count":3},{"next":"but distinct from","previous":"adjoining the fashionable","count":1}]},{"secret_word":"trespasses","clues":[{"next":"as we forgive","previous":"forgive us our","count":12},{"next":"as we forgive","previous":"'forgive us our","count":4},{"next":"neither will your","previous":"not men their","count":3},{"next":"on my lands","previous":"every day committed","count":3},{"next":"your heavenly father","previous":"forgive men their","count":3},{"next":"on your time","previous":"for all my","count":2},{"next":"but as yet","previous":"retrospect my boyish","count":2},{"next":"and i felt","previous":"of other grave","count":1},{"next":"my boy if","previous":"other people s","count":1},{"next":"betray a revolutionary","previous":"established order such","count":1},{"next":"hoping to have","previous":"somebody forgave her","count":1},{"next":"in his neighborhood","previous":"boundaries and cattle","count":1},{"next":"and hawthorne was","previous":"correcting our daily","count":1}]},{"secret_word":"ursule","clues":[{"next":"mirouet a marriage","previous":"a country town","count":9},{"next":"mirouet eugenie grandet","previous":"bachelor s establishment","count":5},{"next":"mirouet a woman","previous":"mistress the peasantry","count":4},{"next":"mirouet a woman","previous":"in life ferragus","count":2},{"next":"mirouet a marriage","previous":"valley father goriot","count":2},{"next":"mirouet maufrigneuse duchesse","previous":"courtesan s life","count":2},{"next":"mirouet eugenie grandet","previous":"the government clerks","count":1},{"next":"we see that","previous":"the case of","count":1},{"next":"mirouet magus elie","previous":"a courtesan's life","count":1},{"next":"mirouet a woman","previous":"eyes the peasantry","count":1},{"next":"mirouet promissory notes","previous":"discoursed upon in","count":1},{"next":"mirouet a woman","previous":"duchesse of langeais","count":1},{"next":"mirouet and les","previous":"menage de garcon","count":1}]},{"secret_word":"v","clues":[{"next":"gm gm v","previous":"by george meredith","count":41},{"next":"chapter vi chapter","previous":"chapter iv chapter","count":28},{"next":"of a back","previous":"and into a","count":1},{"next":"of the shrewd","previous":"and telling chapter","count":1},{"next":"the walk through","previous":"the oak parlour","count":1},{"next":"in which the","previous":"the inn chapter","count":1},{"next":"of his waistcoat","previous":"hand down the","count":1},{"next":"ritables affections taient","previous":"et que ses","count":1},{"next":"cu m'ont r","previous":"parmi lesquels j'ai","count":1},{"next":"nements sont enchain","previous":"candide tous les","count":1},{"next":"ritable succ s","previous":"recueil eut un","count":1},{"next":"lent des analogies","previous":"eprouvons nous r","count":1}]},{"secret_word":"vautrot","clues":[{"next":"had at this","previous":"of the tragedy","count":3},{"next":"as if unconscious","previous":"returned it to","count":3},{"next":"who had so","previous":"to obtain from","count":3},{"next":"heard the sound","previous":"her boudoir and","count":3},{"next":"whose scruples he","previous":"once reverted to","count":3},{"next":"in the meritorious","previous":"therefore in engaging","count":3},{"next":"being careful not","previous":"told her by","count":3},{"next":"baffled like her","previous":"odious suspicions and","count":3},{"next":"humbly who knew","previous":"de camors said","count":3},{"next":"was too prudent","previous":"mystery but as","count":3},{"next":"to her that","previous":"offered to send","count":3},{"next":"had never suspected","previous":"haughtily and though","count":3}]},{"secret_word":"vence","clues":[{"next":"and throw handfuls","previous":"by monsieur paul","count":3},{"next":"has told you","previous":"that monsieur paul","count":3},{"next":"that signs also","previous":"you think monsieur","count":3},{"next":"and bring him","previous":"find him monsieur","count":3},{"next":"wished to introduce","previous":"place when paul","count":3},{"next":"who wishes to","previous":"room for paul","count":3},{"next":"you will go","previous":"madame said paul","count":3},{"next":"i shall not","previous":"madame continued paul","count":3},{"next":"who was near","previous":"sign to paul","count":3},{"next":"with very frivolous","previous":"inspire you monsieur","count":3},{"next":"came into the","previous":"dechartre and paul","count":3},{"next":"said madame martin","previous":"' but monsieur","count":2}]},{"secret_word":"vi","clues":[{"next":"chapter vii chapter","previous":"chapter v chapter","count":28},{"next":"the half of","previous":"of paper chapter","count":1},{"next":"and was rewarded","previous":"that of alfonso","count":1},{"next":"of the diverting","previous":"is continued chapter","count":1},{"next":"had been sent","previous":"fire where charles","count":1},{"next":"volume vii letter","previous":"end of volume","count":1},{"next":"shortly after his","previous":"restored by alfonso","count":1},{"next":"chapter i the","previous":"dark thought book","count":1},{"next":"butternut lane vii","previous":"v on probation","count":1},{"next":"letter xcix abimelech","previous":"volume v volume","count":1},{"next":"of what took","previous":"duly recorded chapter","count":1},{"next":"the half of","previous":"scrap of paper","count":1},{"next":"the minotaur to","previous":"carlyle's mother chapter","count":1}]},{"secret_word":"vicomte","clues":[{"next":"de spoelberch de","previous":"balzac by the","count":21},{"next":"de spoelberch de","previous":"possession of the","count":9},{"next":"de spoelberch de","previous":"d'amour by the","count":3},{"next":"de spoelberch de","previous":"sent by the","count":2},{"next":"de spoelberch de","previous":"collection of the","count":2},{"next":"de spoelberch de","previous":"the scenes the","count":1},{"next":"de spoelberch de","previous":"man as the","count":1},{"next":"de spoelberch de","previous":"hands of the","count":1},{"next":"de spoelberch de","previous":"about and the","count":1},{"next":"de spoelberch de","previous":"add that the","count":1},{"next":"de spoelberch de","previous":"property of the","count":1},{"next":"discovered many other","previous":"quest by the","count":1},{"next":"de spoelberch de","previous":"significant as the","count":1},{"next":"de spoelberche de","previous":"balzac by the","count":1},{"next":"de spoelberch de","previous":"carraud in the","count":1}]},{"secret_word":"vii","clues":[{"next":"chapter viii chapter","previous":"chapter vi chapter","count":28},{"next":"kings xxv etc","previous":"in i kings","count":1},{"next":"centre and watch","previous":"with its henry","count":1},{"next":"of what passed","previous":"whole history chapter","count":1},{"next":"inner hall and","previous":"through the henry","count":1},{"next":"of the second","previous":"ingenious gentleman chapter","count":1},{"next":"an eviction viii","previous":"vi butternut lane","count":1},{"next":"if the reader","previous":"scrutiny of chapter","count":1},{"next":"who certainly is","previous":"emancipation of ferdinand","count":1},{"next":"a disappearance viii","previous":"scrap of paper","count":1},{"next":"as the cid","previous":"reign of alfonso","count":1},{"next":"the first of","previous":"austin gray chapter","count":1}]},{"secret_word":"viii","clues":[{"next":"chapter ix chapter","previous":"chapter vii chapter","count":28},{"next":"ix x xi","previous":"v vi vii","count":8},{"next":"drained the site","previous":"footnote when henry","count":2},{"next":"of the good","previous":"la mancha chapter","count":1},{"next":"and he might","previous":"been a henry","count":1},{"next":"wherein is related","previous":"notable incidents chapter","count":1},{"next":"free grammar school","previous":"master of henry","count":1},{"next":"green lights ix","previous":"vii a disappearance","count":1},{"next":"ambition stirs ix","previous":"vii an eviction","count":1},{"next":"carlyle as man","previous":"vii decadence chapter","count":1},{"next":"children life at","previous":"patriotic poems chapter","count":1},{"next":"anna wenbourne st","previous":"abimelech henley letter","count":1},{"next":"the amiable angler","previous":"georgie howard operator","count":1}]},{"secret_word":"villegry","clues":[{"next":"jacqueline thought nothing","previous":"with madame de","count":3},{"next":"had first introduced","previous":"when madame de","count":3},{"next":"was at pains","previous":"that madame de","count":3},{"next":"leaning back in","previous":"where madame de","count":3},{"next":"with a deep","previous":"said madame de","count":3},{"next":"brought the young","previous":"not madame de","count":3},{"next":"did not talk","previous":"words madame de","count":3},{"next":"was her own","previous":"place madame de","count":3},{"next":"in stead of","previous":"stood madame de","count":3},{"next":"was pouring out","previous":"wearer madame de","count":3},{"next":"had sent to","previous":"gentleman madame de","count":3},{"next":"has sent me","previous":"newcomer madame de","count":3}]},{"secret_word":"vincart","clues":[{"next":"who was lying","previous":"the old man","count":3},{"next":"dozing in his","previous":"the old man","count":3},{"next":"the return to","previous":"to by reine","count":3},{"next":"and the unhappy","previous":"court to reine","count":3},{"next":"farm as unmindful","previous":"could to the","count":3},{"next":"of such treachery","previous":"you accuse mademoiselle","count":3},{"next":"for the last","previous":"without seeing reine","count":3},{"next":"of your return","previous":"company of reine","count":3},{"next":"repeated claudet somewhat","previous":"yes indeed reine","count":3},{"next":"you have relieved","previous":"greatly embarrassed mademoiselle","count":3},{"next":"had sent to","previous":"lilies which mademoiselle","count":3},{"next":"give in explanation","previous":"reasons does mademoiselle","count":3},{"next":"was probably interested","previous":"information that mademoiselle","count":3}]},{"secret_word":"violette","clues":[{"next":"was one went","previous":"of which amedee","count":3},{"next":"was dreamily walking","previous":"this time amedee","count":3},{"next":"enter his studio","previous":"he saw amedee","count":3},{"next":"acting thus by","previous":"only friend amedee","count":3},{"next":"was belated upon","previous":"one evening amedee","count":3},{"next":"incited by jocquelet","previous":"not say that","count":3},{"next":"to this spot","previous":"man urged amedee","count":3},{"next":"above all that","previous":"do not tell","count":3},{"next":"has a never","previous":"see that madame","count":3},{"next":"is almost tempted","previous":"fresh that amedee","count":3},{"next":"and paul sillery","previous":"silvery web amedee","count":3},{"next":"for the first","previous":"surgeon noticed amedee","count":3}]},{"secret_word":"vivey","clues":[{"next":"he made a","previous":"the path to","count":3},{"next":"who comes here","previous":"the shepherd of","count":3},{"next":"tolled for the","previous":"the bells of","count":3},{"next":"and in the","previous":"the park at","count":3},{"next":"seemed more unbearable","previous":"his position at","count":3},{"next":"and tried to","previous":"to returning to","count":3},{"next":"feeling his way","previous":"way back to","count":3},{"next":"after burying at","previous":"himself up at","count":3},{"next":"and i shall","previous":"will return to","count":3},{"next":"and the faint","previous":"defile leading to","count":3},{"next":"going by way","previous":"manette he left","count":3},{"next":"i can't help","previous":"returning despondently to","count":2},{"next":"house which belonged","previous":"and then at","count":1}]},{"secret_word":"wermant","clues":[{"next":"were not wanting","previous":"the three sisters","count":3},{"next":"and the two","previous":"the three demoiselles","count":3},{"next":"or cymier or","previous":"was dancing with","count":3},{"next":"the one who","previous":"on tuesdays raoul","count":3},{"next":"daughter of the","previous":"know that little","count":3},{"next":"crash but those","previous":"suffered by the","count":3},{"next":"to faust and","previous":"fellow compared raoul","count":3},{"next":"elegantly said of","previous":"shelf as raoul","count":3},{"next":"were excellent leaders","previous":"helene and claire","count":3},{"next":"the 'agent de","previous":"the inability of","count":2},{"next":"the 'agent de","previous":"to talk with","count":2},{"next":"gave the best","previous":"don't doubt that","count":2}]},{"secret_word":"why","clues":[{"next":"he should not","previous":"was no reason","count":23},{"next":"you shouldn't have","previous":"i don't see","count":3},{"next":"don't you go","previous":"to take boarders","count":1},{"next":"should i skin","previous":"later to psyche","count":1},{"next":"you can't be","previous":"really any reason","count":1},{"next":"naturally he'd jump","previous":"than she's got","count":1},{"next":"burman isn't as","previous":"i don't see","count":1},{"next":"she was and","previous":"clearly than ever","count":1},{"next":"it's got to","previous":"sound in poker","count":1},{"next":"what's the matter","previous":"hair of the","count":1},{"next":"when she stopped","previous":"glad without knowing","count":1}]},{"secret_word":"wolf","clues":[{"next":"from the door","previous":"to keep the","count":20},{"next":"chased her and","previous":"and a biting","count":1},{"next":"loose among the","previous":"to let the","count":1},{"next":"galley was bearing","previous":"that the she","count":1},{"next":"weary of watching","previous":"as if the","count":1},{"next":"like action and","previous":"on with its","count":1},{"next":"commanded by that","previous":"called the she","count":1},{"next":"and lamb i","previous":"went on for","count":1},{"next":"s eyes from","previous":"sea like a","count":1},{"next":"s mouth as","previous":"dark as a","count":1},{"next":"at all and","previous":"wasn't a biting","count":1},{"next":"s savage howl","previous":"roar the fierce","count":1},{"next":"s skin for","previous":"baldric of sea","count":1}]},{"secret_word":"x","clues":[{"next":"chapter xi chapter","previous":"chapter ix chapter","count":23},{"next":"plus y at","previous":"i should think","count":2},{"next":"y and z","previous":"and of privates","count":1},{"next":"on which the","previous":"the kur'an surah","count":1},{"next":"midnight vigils part","previous":"a french exile","count":1},{"next":"does not suit","previous":"then tender veracious","count":1},{"next":"wherein is related","previous":"seen there chapter","count":1},{"next":"across her breast","previous":"hands in an","count":1},{"next":"of the pleasant","previous":"valiant manchegan chapter","count":1},{"next":"to a five","previous":"signed his famous","count":1},{"next":"condition repaired to","previous":"landlord in the","count":1},{"next":"the princess comes","previous":"stirs ix buttons","count":1}]},{"secret_word":"xi","clues":[{"next":"chapter xii chapter","previous":"chapter x chapter","count":22},{"next":"xii xiii xiv","previous":"viii ix x","count":7},{"next":"of the strange","previous":"are true chapter","count":1},{"next":"the southern cross","previous":"the cove chapter","count":1},{"next":"the state takes","previous":"born king chapter","count":1},{"next":"the southern cross","previous":"in the cove","count":1},{"next":"'for my part","previous":"to conclude speech","count":1},{"next":"xiii five illustrations","previous":"three consecutive letters","count":1},{"next":"the state takes","previous":"comes to grief","count":1},{"next":"you can't play","previous":"x midnight prowlers","count":1},{"next":"it was monday","previous":"jerky eccentric incoherent","count":1},{"next":"of what befell","previous":"sancho panza chapter","count":1}]},{"secret_word":"xii","clues":[{"next":"chapter xiii chapter","previous":"chapter xi chapter","count":21},{"next":"xiii xiv xv","previous":"ix x xi","count":7},{"next":"of sweden to","previous":"march of charles","count":2},{"next":"emperor of the","previous":"tragedy of 'ibrahim","count":2},{"next":"tom turns the","previous":"the southern cross","count":1},{"next":"of the strange","previous":"of death chapter","count":1},{"next":"precy sur oise","previous":"of chantilly chapter","count":1},{"next":"of what a","previous":"certain goatherds chapter","count":1},{"next":"clarke's xiii eight","previous":"takes a hand","count":1},{"next":"vivian read the","previous":"you sybilla chapter","count":1},{"next":"them damn' snake","previous":"play with me","count":1},{"next":"letters on the","previous":"views laureateship chapter","count":1}]},{"secret_word":"xiii","clues":[{"next":"chapter xiv chapter","previous":"chapter xii chapter","count":20},{"next":"xiv xv xvi","previous":"x xi xii","count":5},{"next":"lviii lx lxii","previous":"love x xi","count":1},{"next":"in which is","previous":"the mirrors chapter","count":1},{"next":"eight to six","previous":"hand xii clarke's","count":1},{"next":"cloud sign versus","previous":"them damn' snake","count":1},{"next":"lady de courcy","previous":"reginald de courcy","count":1},{"next":"in which is","previous":"don quixote chapter","count":1},{"next":"madame de la","previous":"turns the tables","count":1},{"next":"five illustrations drawn","previous":"consecutive letters xi","count":1},{"next":"and transcripts of","previous":"cuneiform texts part","count":1},{"next":"plate and ebellog","previous":"cuneiform texts part","count":1}]},{"secret_word":"xiv","clues":[{"next":"chapter xv chapter","previous":"chapter xiii chapter","count":20},{"next":"xv xvi xvii","previous":"xi xii xiii","count":5},{"next":"they would not","previous":"actions of lewis","count":2},{"next":"he lost the","previous":"iii against louis","count":2},{"next":"wherein is continued","previous":"two squires chapter","count":1},{"next":"who said it","previous":"it was lewis","count":1},{"next":"wherein are inserted","previous":"other incidents chapter","count":1},{"next":"in the fog","previous":"de la fontaine","count":1},{"next":"'i make an","previous":"' said lewis","count":1},{"next":"the claim jumpers","previous":"sign versus cupid","count":1},{"next":"idleness xv marking","previous":"eight to six","count":1},{"next":"continues 'mais un","previous":"reign of lewis","count":1}]},{"secret_word":"xix","clues":[{"next":"chapter xx chapter","previous":"chapter xviii chapter","count":17},{"next":"xx xxi xxii","previous":"xvi xvii xviii","count":3},{"next":"mistaking it for","previous":"figure of number","count":2},{"next":"preparations for flight","previous":"the first night","count":1},{"next":"in which is","previous":"the common chapter","count":1},{"next":"evadna goes calling","previous":"the rim rock","count":1},{"next":"in which he","previous":"from the sonnet","count":1},{"next":"century the villa","previous":"beginning of the","count":1},{"next":"of the shrewd","previous":"worth relating chapter","count":1},{"next":"the fight for","previous":"declaration of war","count":1},{"next":"coke clifton to","previous":"volume ii letter","count":1},{"next":"the attack xx","previous":"avenue of maples","count":1},{"next":"c sar s","previous":"sar aut nihil","count":1}]},{"secret_word":"xv","clues":[{"next":"chapter xvi chapter","previous":"chapter xiv chapter","count":20},{"next":"xvi xvii xviii","previous":"xii xiii xiv","count":5},{"next":"squaw talk far","previous":"the claim jumpers","count":1},{"next":"wherein it is","previous":"the grove chapter","count":1},{"next":"nancy xvi madame","previous":"in the fog","count":1},{"next":"gilt boiseries the","previous":"their perfect louis","count":1},{"next":"being delighted with","previous":"place de louis","count":1},{"next":"in which is","previous":"looked for chapter","count":1},{"next":"marking time xvi","previous":"six xiv idleness","count":1},{"next":"driveller juan and","previous":"xiv intransigence lost","count":1},{"next":"and xvi centuries","previous":"sculptures of the","count":1}]},{"secret_word":"xvi","clues":[{"next":"chapter xvii chapter","previous":"chapter xv chapter","count":17},{"next":"xvii xviii xix","previous":"xiii xiv xv","count":5},{"next":"centuries badges of","previous":"the xv and","count":1},{"next":"pity a mask","previous":"the cub slut","count":1},{"next":"he meant his","previous":"the transgressor chapter","count":1},{"next":"don't get excited","previous":"off heap smart","count":1},{"next":"lewis xviii and","previous":"children afterwards lewis","count":1},{"next":"of what befell","previous":"squire were chapter","count":1},{"next":"miss bobinet's xvii","previous":"xv marking time","count":1},{"next":"of what happened","previous":"heartless yanguesans chapter","count":1},{"next":"vous qui n'avez","previous":"en occuper louis","count":1},{"next":"madame at the","previous":"fog xv nancy","count":1}]},{"secret_word":"xvii","clues":[{"next":"chapter xviii chapter","previous":"chapter xvi chapter","count":17},{"next":"xviii xix xx","previous":"xiv xv xvi","count":3},{"next":"wherein is shown","previous":"la mancha chapter","count":1},{"next":"evil days xviii","previous":"of a pope","count":1},{"next":"in which are","previous":"a castle chapter","count":1},{"next":"the stuffed owl","previous":"in charleville chapter","count":1},{"next":"the marquis leaves","previous":"at the inn","count":1},{"next":"voyage to lisbon","previous":"law reform chapter","count":1},{"next":"xxviii xxxiii lxvi","previous":"self love i","count":1},{"next":"behind the twinkling","previous":"xvi miss bobinet's","count":1},{"next":"first victory xviii","previous":"mask of cowardice","count":1},{"next":"the red angel","previous":"dragon s grandmother","count":1},{"next":"the honourable mrs","previous":"abimelech henley letter","count":1}]},{"secret_word":"xviii","clues":[{"next":"chapter xix chapter","previous":"chapter xvii chapter","count":17},{"next":"and she was","previous":"days of louis","count":3},{"next":"xix xx xxi","previous":"xv xvi xvii","count":3},{"next":"of what happened","previous":"the lions chapter","count":1},{"next":"the first night","previous":"the twinkling lights","count":1},{"next":"the avenue of","previous":"the inn chapter","count":1},{"next":"in which is","previous":"a castle chapter","count":1},{"next":"the avenue of","previous":"on the inn","count":1},{"next":"a shot from","previous":"little target practice","count":1},{"next":"civ i ff","previous":"footnote compare psalms","count":1},{"next":"and charles x","previous":"lewis xvi lewis","count":1}]},{"secret_word":"yves","clues":[{"next":"than for me","previous":"not more for","count":4},{"next":"and i in","previous":"we shall go","count":4},{"next":"and the two","previous":"once more with","count":4},{"next":"has any feeling","previous":"me than for","count":4},{"next":"who will not","previous":"therefore come for","count":4},{"next":"am quite disposed","previous":"about my poor","count":4},{"next":"and chrysantheme i","previous":"the parting between","count":3},{"next":"chrysantheme madame prune","previous":"a helping hand","count":3},{"next":"chrysantheme oyouki and","previous":"to the town","count":3},{"next":"about chrysantheme it","previous":"to speak to","count":3},{"next":"of bygone days","previous":"finding my stanch","count":3},{"next":"who in visiting","previous":"thieves fashion remarks","count":3}]},{"secret_word":"zibeline","clues":[{"next":"who had come","previous":"and he beheld","count":3},{"next":"on the litter","previous":"the general placed","count":3},{"next":"on the subject","previous":"the mystery surrounding","count":3},{"next":"apparently intended to","previous":"the grand stand","count":3},{"next":"had gone over","previous":"of the shock","count":3},{"next":"awaited the three","previous":"a bridge where","count":3},{"next":"at the end","previous":"he should find","count":3},{"next":"riding with their","previous":"not to find","count":3},{"next":"and i have","previous":"last night said","count":3},{"next":"on the other","previous":"fence landed beside","count":3},{"next":"lay then he","previous":"mattress on which","count":3},{"next":"by phillipe de","previous":"by david widger","count":1}]}] \ No newline at end of file diff --git a/server/db/init.sql b/server/db/init.sql new file mode 100644 index 0000000..af1fa9d --- /dev/null +++ b/server/db/init.sql @@ -0,0 +1,33 @@ +create table if not exists app_users ( + id serial primary key, + username text not null unique, + password_hash text not null, + created_at timestamptz not null default now() +); + +create table if not exists project ( + id serial primary key, + name text not null, + description text not null default '', + created_at timestamptz not null default now() +); + +create table if not exists task ( + id serial primary key, + project_id int not null references project(id) on delete cascade, + title text not null, + description text not null default '', + status text not null default 'todo' check (status in ('todo', 'doing', 'done')), + assignee text not null default '', + assignees text not null default '', + due_date date, + created_at timestamptz not null default now() +); + +alter table task add column if not exists assignees text not null default ''; + +create table if not exists session ( + token text primary key, + user_id int not null references app_users(id) on delete cascade, + expires_at timestamptz not null +); diff --git a/server/gleam.toml b/server/gleam.toml new file mode 100644 index 0000000..9559b8d --- /dev/null +++ b/server/gleam.toml @@ -0,0 +1,34 @@ +name = "server" +version = "1.0.0" + +# Fill out these fields if you intend to generate HTML documentation or publish +# your project to the Hex package manager. +# +# description = "" +# licences = ["Apache-2.0"] +# repository = { type = "github", user = "", repo = "" } +# links = [{ title = "Website", href = "" }] +# +# For a full reference of all the available options, you can have a look at +# https://gleam.run/writing-gleam/gleam-toml/. + +[dependencies] +gleam_stdlib = ">= 1.0.0 and < 2.0.0" +gleam_erlang = ">= 1.3.0 and < 2.0.0" +gleam_otp = ">= 1.3.0 and < 2.0.0" +gleam_http = ">= 4.4.0 and < 5.0.0" +lustre = ">= 5.7.1 and < 6.0.0" +mist = ">= 6.0.3 and < 7.0.0" +simplifile = ">= 2.7.0 and < 3.0.0" +shared = { path = "../shared" } +gleam_json = ">= 3.1.0 and < 4.0.0" +birl = ">= 2.0.0 and < 3.0.0" +wisp = ">= 2.2.2 and < 3.0.0" +pog = ">= 4.1.0 and < 5.0.0" +envoy = ">= 1.0.0 and < 2.0.0" +squirrel = ">= 4.7.0 and < 5.0.0" +gleam_crypto = ">= 1.5.0 and < 2.0.0" + +[dev_dependencies] +gleeunit = ">= 1.0.0 and < 2.0.0" +gsh = ">= 1.1.9 and < 2.0.0" diff --git a/server/justfile b/server/justfile new file mode 100644 index 0000000..f878333 --- /dev/null +++ b/server/justfile @@ -0,0 +1,7 @@ +build: + cd ../client && gleam run -m lustre/dev build --outdir=../server/static --no-html=true + cd - + +run: build + gleam run + diff --git a/server/manifest.toml b/server/manifest.toml new file mode 100644 index 0000000..3b14f08 --- /dev/null +++ b/server/manifest.toml @@ -0,0 +1,85 @@ +# Do not manually edit this file, it is managed by Gleam. +# +# This file locks the dependency versions used, to make your build +# deterministic and to prevent unexpected versions from being included +# in your application. +# +# You should check this file into your source control repository. + +packages = [ + { name = "argv", version = "1.1.0", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "3277D100448BDB4A29B6D58C0F36F631CBC349E8BDD09766C6309DF202831140" }, + { name = "backoff", version = "1.1.6", build_tools = ["rebar3"], requirements = [], otp_app = "backoff", source = "hex", outer_checksum = "CF0CFFF8995FB20562F822E5CC47D8CCF664C5ECDC26A684CBE85C225F9D7C39" }, + { name = "birl", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_regexp", "gleam_stdlib", "gleam_time", "ranger"], otp_app = "birl", source = "hex", outer_checksum = "51F9D18050231ED8A324A5A87C07F2582E22C1CA8BBDEC213623A7B39AF060F1" }, + { name = "contour", version = "1.2.1", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_stdlib", "glexer", "houdini"], otp_app = "contour", source = "hex", outer_checksum = "C7895472BBAAC5D15DBDBAF6DD1847F6981F2F6132F726BAD30434A6E3BAAB95" }, + { name = "directories", version = "1.2.0", build_tools = ["gleam"], requirements = ["envoy", "gleam_stdlib", "platform", "simplifile"], otp_app = "directories", source = "hex", outer_checksum = "D13090CFCDF6759B87217E8DDD73A75903A700148A82C1D33799F333E249BF9E" }, + { name = "envoy", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "envoy", source = "hex", outer_checksum = "9C6FBB6BFA02A52798BEEC5977A738CAD6E4A057F4B67FD0C8061AD2502C191A" }, + { name = "etch", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "etch", source = "hex", outer_checksum = "A4B4458EE1E7D22753538C03F0D64C930309863365D2D26570E2D2C6B7CFC5EA" }, + { name = "etch_erlang", version = "1.1.0", build_tools = ["gleam"], requirements = ["etch", "gleam_erlang", "gleam_stdlib"], otp_app = "etch_erlang", source = "hex", outer_checksum = "CDD5BCBF680A97AF979EF1FD18F4E39E64DA2D7938422DEF938A69F26B38BF32" }, + { name = "eval", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "eval", source = "hex", outer_checksum = "264DAF4B49DF807F303CA4A4E4EBC012070429E40BE384C58FE094C4958F9BDA" }, + { name = "exception", version = "2.1.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "6BDEA95248093599391C3B5DF1835C5C6A86C353C2F99CE539B450E3432FE117" }, + { name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" }, + { name = "format", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "format", source = "hex", outer_checksum = "7654EE35E01394BF558F364542F163941A66CBA1512AA7D53F2A794BBD90BD9D" }, + { name = "glam", version = "2.0.4", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glam", source = "hex", outer_checksum = "48A043A12091F93D911C316DD8F7FFD03CD9FF6F50848FC56E359D3C168DF0FA" }, + { name = "glance", version = "7.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glexer"], otp_app = "glance", source = "hex", outer_checksum = "EA52986965408D43003A1760E41457493EB96098DE193E6AD8646930EC190CB9" }, + { name = "gleam_community_ansi", version = "1.5.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_regexp", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "B5AA433AF84313E23FDF90CCFF752B9380FE9FFCE02B2949D49B7AACCC77B16D" }, + { name = "gleam_community_colour", version = "2.0.4", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "6DB4665555D7D2B27F0EA32EF47E8BEBC4303821765F9C73D483F38EE24894F0" }, + { name = "gleam_crypto", version = "1.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "2DE9E4EF53CF6FEE049D4F765731F7178F7A11AEFAE00EEE63BF7536B354AD3F" }, + { name = "gleam_erlang", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "1124AD3AA21143E5AF0FC5CF3D9529F6DB8CA03E43A55711B60B6B7B3874375C" }, + { name = "gleam_http", version = "4.4.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "F065CE9941A7756ABBAEAE7F9F32A96CAD29DA3311A381DB2D926EA8E8C156DC" }, + { name = "gleam_json", version = "3.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "44FDAA8847BE8FC48CA7A1C089706BD54BADCC4C45B237A992EDDF9F2CDB2836" }, + { name = "gleam_otp", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "DE4CA6850842F0266EE95317A25DD6A0A0F20CDFAB7C0ADC2E63251D7C3C72EC" }, + { name = "gleam_regexp", version = "1.1.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "9C215C6CA84A5B35BB934A9B61A9A306EC743153BE2B0425A0D032E477B062A9" }, + { name = "gleam_stdlib", version = "1.0.5", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "CEE5B6C076A85B45F60C585F4316C63EC8B7127C119D5738C3958A9C4D50404E" }, + { name = "gleam_time", version = "1.10.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_time", source = "hex", outer_checksum = "56539216E4C4B1748714652AB38F0BD16B9101F61DB62769FDC7CD42A8E5E833" }, + { name = "gleam_yielder", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_yielder", source = "hex", outer_checksum = "8E4E4ECFA7982859F430C57F549200C7749823C106759F4A19A78AEA6687717A" }, + { name = "gleeunit", version = "1.11.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "EC31ABA74256AEA531EDF8169931D775BBB384FED0A8A1BDC4DD9354E3E21826" }, + { name = "glexer", version = "2.5.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "splitter"], otp_app = "glexer", source = "hex", outer_checksum = "D423CF63B8D4F9654EF53D0AF4904B249EB0679BD41C63440170AC508C9CC65E" }, + { name = "glisten", version = "9.0.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib", "logging"], otp_app = "glisten", source = "hex", outer_checksum = "7795AA50830656F3A0316A6B26595F893C83272DA901B3405E31339CAA31A10B" }, + { name = "gramps", version = "6.0.1", build_tools = ["gleam"], requirements = ["gleam_crypto", "gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gramps", source = "hex", outer_checksum = "D55636072DEE173F6586A5679D3C02EC7A0DE3F8646B78C351B72908FF223DF7" }, + { name = "gsh", version = "1.1.9", build_tools = ["gleam"], requirements = ["contour", "etch", "etch_erlang", "format", "glance", "gleam_erlang", "gleam_json", "gleam_stdlib", "glexer", "in", "shellout", "simplifile", "tom"], otp_app = "gsh", source = "hex", outer_checksum = "8342B1CBA3430EA727D7D82D8AF11DAB85E79B446D8BE0B5A5A45E240F9C5AB1" }, + { name = "houdini", version = "1.2.1", build_tools = ["gleam"], requirements = [], otp_app = "houdini", source = "hex", outer_checksum = "6F8AC2F12974567FB744BEA66AC93CEB76AAEA19AD28564623F76CDA9BC26A85" }, + { name = "hpack_erl", version = "0.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "hpack", source = "hex", outer_checksum = "D6137D7079169D8C485C6962DFE261AF5B9EF60FBC557344511C1E65E3D95FB0" }, + { name = "in", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "in", source = "hex", outer_checksum = "5339494529936AF83EAA0B8368195DCA9505382836CDED4CD6B0F5F9FA93C2B8" }, + { name = "justin", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "justin", source = "hex", outer_checksum = "8B1C62269E8607D0A0ED698B7903984CE0BF7B6B3C0DEA3C6C8302B39402837B" }, + { name = "logging", version = "1.5.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "logging", source = "hex", outer_checksum = "BC5F18CE5DD9686100229FE5409BDC3DD5C46D5A7DF2F804AD2D8F0DD6C5060E" }, + { name = "lustre", version = "5.7.1", build_tools = ["gleam"], requirements = ["exception", "gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib", "houdini"], otp_app = "lustre", source = "hex", outer_checksum = "663A2D1A3458914CA537A42AC07E601DD3FD85415EBDAF4717F2DFF6E86F90F9" }, + { name = "marceau", version = "1.3.0", build_tools = ["gleam"], requirements = [], otp_app = "marceau", source = "hex", outer_checksum = "2D1C27504BEF45005F5DFB18591F8610FB4BFA91744878210BDC464412EC44E9" }, + { name = "mist", version = "6.0.3", build_tools = ["gleam"], requirements = ["exception", "gleam_erlang", "gleam_http", "gleam_otp", "gleam_stdlib", "glisten", "gramps", "hpack_erl", "logging"], otp_app = "mist", source = "hex", outer_checksum = "1B07F321D5FA0CB162D81496F2DE96AEB6EF8980F4F38230A4CC3F849497E020" }, + { name = "mug", version = "3.1.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "mug", source = "hex", outer_checksum = "C01279D98E40371DA23461774B63F0E3581B8F1396049D881B0C7EB32799D93F" }, + { name = "non_empty_list", version = "2.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "non_empty_list", source = "hex", outer_checksum = "06F9D3AC751CF7853AD5D24B8139CEB30E42D8799DE8D49F966A6197DF0B01CC" }, + { name = "opentelemetry_api", version = "1.5.0", build_tools = ["rebar3", "mix"], requirements = [], otp_app = "opentelemetry_api", source = "hex", outer_checksum = "F53EC8A1337AE4A487D43AC89DA4BD3A3C99DDF576655D071DEED8B56A2D5DDA" }, + { name = "pg_types", version = "0.6.0", build_tools = ["rebar3"], requirements = [], otp_app = "pg_types", source = "hex", outer_checksum = "9949A4849DD13408FA249AB7B745E0D2DFDB9532AEE2B9722326E33CD082A778" }, + { name = "pgo", version = "0.20.0", build_tools = ["rebar3"], requirements = ["backoff", "opentelemetry_api", "pg_types"], otp_app = "pgo", source = "hex", outer_checksum = "2F11E6649CEB38E569EF56B16BE1D04874AE5B11A02867080A2817CE423C683B" }, + { name = "platform", version = "1.0.0", build_tools = ["gleam"], requirements = [], otp_app = "platform", source = "hex", outer_checksum = "8339420A95AD89AAC0F82F4C3DB8DD401041742D6C3F46132A8739F6AEB75391" }, + { name = "pog", version = "4.1.0", build_tools = ["gleam"], requirements = ["exception", "gleam_erlang", "gleam_otp", "gleam_stdlib", "gleam_time", "pgo"], otp_app = "pog", source = "hex", outer_checksum = "E4AFBA39A5FAA2E77291836C9683ADE882E65A06AB28CA7D61AE7A3AD61EBBD5" }, + { name = "ranger", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_yielder"], otp_app = "ranger", source = "hex", outer_checksum = "C8988E8F8CDBD3E7F4D8F2E663EF76490390899C2B2885A6432E942495B3E854" }, + { name = "shared", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib", "simplifile"], source = "local", path = "../shared" }, + { name = "shellout", version = "1.8.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "shellout", source = "hex", outer_checksum = "C416356D45151F298108C9DB9CD1EDE0313F620B5EDBB5766CD7237659D87841" }, + { name = "simplifile", version = "2.7.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "A2727627B063E87351934C7F7F008F2D1FDB16F6DE0B8C79F9E46459CFC9C164" }, + { name = "splitter", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "splitter", source = "hex", outer_checksum = "8F1485306E0D59168A39E12ED8844F9F616EC59C3C63AFCFDAE04DBD68690CBC" }, + { name = "squirrel", version = "4.7.0", build_tools = ["gleam"], requirements = ["argv", "envoy", "eval", "filepath", "glam", "gleam_community_ansi", "gleam_crypto", "gleam_json", "gleam_regexp", "gleam_stdlib", "gleam_time", "glexer", "justin", "mug", "non_empty_list", "pog", "simplifile", "splitter", "term_size", "tom", "tote", "youid"], otp_app = "squirrel", source = "hex", outer_checksum = "DD7D42F5EFE5E0FF597CF6D8E770C6327A7B10589BFCD3144EDC852AE2F6F0DE" }, + { name = "term_size", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "term_size", source = "hex", outer_checksum = "D00BD2BC8FB3EBB7E6AE076F3F1FF2AC9D5ED1805F004D0896C784D06C6645F1" }, + { name = "tom", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_time"], otp_app = "tom", source = "hex", outer_checksum = "DCF04CB7AB35D58CFC598C66EA2E1816D160759802C89B2BA6238780D59BC256" }, + { name = "tote", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "tote", source = "hex", outer_checksum = "30CBB77B72867B1DE2D271A7FE61DBE8BB81CA7DC385A0E1FDF7D38E71F3791A" }, + { name = "wisp", version = "2.2.2", build_tools = ["gleam"], requirements = ["directories", "exception", "filepath", "gleam_crypto", "gleam_erlang", "gleam_http", "gleam_json", "gleam_stdlib", "houdini", "logging", "marceau", "mist", "simplifile"], otp_app = "wisp", source = "hex", outer_checksum = "5FF5F1E288C3437252ABB93D8F9CF42FF652CE7AD54480CFE736038DC09C4F22" }, + { name = "youid", version = "1.6.0", build_tools = ["gleam"], requirements = ["gleam_crypto", "gleam_stdlib", "gleam_time"], otp_app = "youid", source = "hex", outer_checksum = "7A3ABA44B1B38BC2BDCB5474C5317AA372BE58DFBC649815EE08B03526DDA18D" }, +] + +[requirements] +birl = { version = ">= 2.0.0 and < 3.0.0" } +envoy = { version = ">= 1.0.0 and < 2.0.0" } +gleam_crypto = { version = ">= 1.5.0 and < 2.0.0" } +gleam_erlang = { version = ">= 1.3.0 and < 2.0.0" } +gleam_http = { version = ">= 4.4.0 and < 5.0.0" } +gleam_json = { version = ">= 3.1.0 and < 4.0.0" } +gleam_otp = { version = ">= 1.3.0 and < 2.0.0" } +gleam_stdlib = { version = ">= 1.0.0 and < 2.0.0" } +gleeunit = { version = ">= 1.0.0 and < 2.0.0" } +gsh = { version = ">= 1.1.9 and < 2.0.0" } +lustre = { version = ">= 5.7.1 and < 6.0.0" } +mist = { version = ">= 6.0.3 and < 7.0.0" } +pog = { version = ">= 4.1.0 and < 5.0.0" } +shared = { path = "../shared" } +simplifile = { version = ">= 2.7.0 and < 3.0.0" } +squirrel = { version = ">= 4.7.0 and < 5.0.0" } +wisp = { version = ">= 2.2.2 and < 3.0.0" } diff --git a/server/src/database.gleam b/server/src/database.gleam new file mode 100644 index 0000000..859f02d --- /dev/null +++ b/server/src/database.gleam @@ -0,0 +1,23 @@ +import envoy +import gleam/erlang/process +import gleam/otp/static_supervisor +import gleam/result +import pog + +pub type Database { + Database(connection: pog.Connection) +} + +pub fn start() -> Result(Database, Nil) { + let name = process.new_name("iron_claw_db") + echo "getting url" + use url <- result.try(envoy.get("DATABASE_URL")) + echo url + use config <- result.try(pog.url_config(name, url)) + echo "config" + let assert Ok(_) = + static_supervisor.new(static_supervisor.OneForOne) + |> static_supervisor.add(pog.supervised(config)) + |> static_supervisor.start + Ok(Database(pog.named_connection(name))) +} diff --git a/server/src/server.gleam b/server/src/server.gleam new file mode 100644 index 0000000..f7452c1 --- /dev/null +++ b/server/src/server.gleam @@ -0,0 +1,312 @@ +import database.{type Database} +import envoy +import gleam/bit_array +import gleam/crypto +import gleam/erlang/process +import gleam/http +import gleam/int +import gleam/io +import gleam/json +import gleam/list +import gleam/result +import gleam/string +import mist +import pog +import shared +import simplifile +import sql +import wisp.{type Request, type Response} +import wisp/wisp_mist + +pub fn main() -> Nil { + wisp.configure_logger() + let assert Ok(db) = database.start() + let assert Ok(schema) = simplifile.read("./db/init.sql") + let assert Ok(_) = initialize_schema(db, schema) + let secret = + envoy.get("SESSION_SECRET") + |> result.unwrap("iron-claw-development-secret-change-me") + let assert Ok(_) = + handle_request(db, _) + |> wisp_mist.handler(secret) + |> mist.new + |> mist.port( + envoy.get("PORT") + |> result.unwrap("3000") + |> int.parse + |> result.unwrap(3000), + ) + |> mist.start + process.sleep_forever() +} + +fn initialize_schema( + db: Database, + schema: String, +) -> Result(Nil, pog.QueryError) { + schema + |> string.split(";") + |> list.map(string.trim) + |> list.filter(fn(statement) { statement != "" }) + |> list.try_fold(Nil, fn(_, statement) { + pog.query(statement) + |> pog.execute(db.connection) + |> result.map(fn(_) { Nil }) + }) +} + +fn handle_request(db: Database, request: Request) -> Response { + use req <- middleware(request) + case req.method, wisp.path_segments(req) { + http.Get, [] -> shell() + http.Get, ["login"] -> shell() + http.Get, ["register"] -> shell() + http.Get, ["api", "dashboard"] -> api_dashboard(db, req) + http.Get, ["api", "logout"] -> logout(req) + http.Post, ["api", "login"] -> + json_body(req, fn(body) { login(db, req, body) }) + http.Post, ["api", "register"] -> + json_body(req, fn(body) { register(db, req, body) }) + http.Post, ["api", "projects"] -> + json_body(req, fn(body) { add_project(db, req, body) }) + http.Post, ["api", "projects", project_id, "tasks"] -> + json_body(req, fn(body) { add_task(db, req, project_id, body) }) + http.Post, ["api", "tasks", task_id, "status"] -> + json_body(req, fn(body) { change_status(db, req, task_id, body) }) + _, _ -> wisp.not_found() + } +} + +fn middleware(req: Request, next: fn(Request) -> Response) -> Response { + use <- wisp.log_request(req) + use <- wisp.rescue_crashes + wisp.handle_head(req, fn(req) { + wisp.serve_static(req, under: "/static", from: "./static", next: fn() { + next(req) + }) + }) +} + +fn shell() -> Response { + wisp.html_response( + "Iron Claw
", + 200, + ) +} + +fn api_dashboard(db: Database, req: Request) -> Response { + case current_user(db, req) { + Error(_) -> wisp.json_response("{\"error\":\"unauthorized\"}", 401) + Ok(username) -> { + let projects = + rows([], sql.list_projects(db.connection)) + |> list.map(fn(project: sql.Project) { + shared.Project( + id: project.id, + name: project.name, + description: project.description, + tasks: rows([], sql.list_tasks(db.connection, project.id)) + |> list.map(to_shared_task), + ) + }) + shared.Dashboard(username:, projects:) + |> shared.dashboard_json + |> json.to_string + |> wisp.json_response(200) + } + } +} + +fn login(db: Database, req: Request, body: String) -> Response { + case json.parse(body, shared.credentials_decoder()) { + Ok(credentials) -> + case sql.find_user(db.connection, credentials.username) { + Ok(pog.Returned(_, [user])) -> + case secure_compare(user.password_hash, credentials.password) { + True -> start_session(db, req, user.id) + False -> + wisp.json_response("{\"error\":\"invalid credentials\"}", 401) + } + _ -> wisp.json_response("{\"error\":\"invalid credentials\"}", 401) + } + Error(_) -> wisp.json_response("{\"error\":\"invalid JSON\"}", 400) + } +} + +fn register(db: Database, req: Request, body: String) -> Response { + case json.parse(body, shared.credentials_decoder()) { + Ok(credentials) -> + case + string.length(credentials.username) >= 3 + && string.length(credentials.password) >= 8 + { + True -> + case + sql.create_user( + db.connection, + credentials.username, + password_hash(credentials.password), + ) + { + Ok(pog.Returned(_, [user_id])) -> start_session(db, req, user_id) + Error(error) -> registration_error(error) + Ok(_) -> + wisp.json_response("{\"error\":\"username unavailable\"}", 409) + } + + False -> + wisp.json_response( + "{\"error\":\"username and password are required\"}", + 400, + ) + } + _ -> + wisp.json_response( + "{\"error\":\"username and password are required\"}", + 400, + ) + } +} + +fn registration_error(error: pog.QueryError) -> Response { + case error { + pog.ConstraintViolated(_, _, _) -> + wisp.json_response("{\"error\":\"username unavailable\"}", 409) + _ -> { + io.println("registration database error: " <> query_error_name(error)) + wisp.json_response("{\"error\":\"database unavailable\"}", 503) + } + } +} + +fn query_error_name(error: pog.QueryError) -> String { + case error { + pog.ConstraintViolated(message, _, _) -> message + pog.PostgresqlError(_, name, message) -> name <> ": " <> message + pog.UnexpectedArgumentCount(_, _) -> "unexpected argument count" + pog.UnexpectedArgumentType(_, _) -> "unexpected argument type" + pog.UnexpectedResultType(_) -> "unexpected result type" + pog.QueryTimeout -> "query timeout" + pog.ConnectionUnavailable -> "connection unavailable" + } +} + +fn start_session(db: Database, req: Request, user_id: Int) -> Response { + let token = wisp.random_string(48) + let assert Ok(_) = sql.create_session(db.connection, token, user_id) + wisp.json_response("{\"ok\":true}", 200) + |> wisp.set_cookie(req, "session", token, wisp.Signed, 2_592_000) +} + +fn add_project(db: Database, req: Request, body: String) -> Response { + case current_user(db, req), json.parse(body, shared.new_project_decoder()) { + Ok(_), Ok(project) -> { + let assert Ok(_) = + sql.create_project(db.connection, project.name, project.description) + wisp.json_response("{\"ok\":true}", 201) + } + _, _ -> wisp.json_response("{\"error\":\"unauthorized\"}", 401) + } +} + +fn add_task( + db: Database, + req: Request, + project_id: String, + body: String, +) -> Response { + case + current_user(db, req), + int.parse(project_id), + json.parse(body, shared.new_task_decoder()) + { + Ok(_), Ok(id), Ok(task) -> { + let assert Ok(_) = + sql.create_task( + db.connection, + id, + task.title, + task.description, + task.assignee, + task.assignees, + task.due_date, + ) + wisp.json_response("{\"ok\":true}", 201) + } + _, _, _ -> wisp.json_response("{\"error\":\"invalid request\"}", 400) + } +} + +fn change_status( + db: Database, + req: Request, + task_id: String, + body: String, +) -> Response { + case + current_user(db, req), + int.parse(task_id), + json.parse(body, shared.status_change_decoder()) + { + Ok(_), Ok(id), Ok(change) -> { + let assert Ok(_) = + sql.update_task_status(db.connection, change.status, id) + wisp.json_response("{\"ok\":true}", 200) + } + _, _, _ -> wisp.json_response("{\"error\":\"invalid request\"}", 400) + } +} + +fn logout(req: Request) -> Response { + wisp.json_response("{\"ok\":true}", 200) + |> wisp.set_cookie(req, "session", "", wisp.Signed, 0) +} + +fn json_body(req: Request, next: fn(String) -> Response) -> Response { + wisp.require_string_body(req, next) +} + +fn current_user(db: Database, req: Request) -> Result(String, Nil) { + use token <- result.try(wisp.get_cookie(req, "session", wisp.Signed)) + echo token + case sql.find_session(db.connection, token) { + Ok(pog.Returned(_, [user_id])) -> + case sql.find_username(db.connection, user_id) { + Ok(pog.Returned(_, [username])) -> Ok(username) + _ -> Error(Nil) + } + _ -> Error(Nil) + } +} + +fn to_shared_task(task: sql.Task) -> shared.Task { + shared.Task( + id: task.id, + project_id: task.project_id, + title: task.title, + description: task.description, + status: task.status, + assignee: task.assignee, + assignees: task.assignees, + due_date: task.due_date, + ) +} + +fn rows( + default: List(a), + value: Result(pog.Returned(a), pog.QueryError), +) -> List(a) { + case value { + Ok(pog.Returned(_, values)) -> values + Error(_) -> default + } +} + +fn password_hash(password: String) -> String { + crypto.hash(crypto.Sha512, <>) + |> bit_array.base64_encode(False) +} + +fn secure_compare(stored: String, password: String) -> Bool { + stored == password_hash(password) +} diff --git a/server/src/sql.gleam b/server/src/sql.gleam new file mode 100644 index 0000000..96d6464 --- /dev/null +++ b/server/src/sql.gleam @@ -0,0 +1,155 @@ +import gleam/dynamic/decode +import pog + +pub type User { + User(id: Int, username: String, password_hash: String) +} + +pub type Project { + Project(id: Int, name: String, description: String) +} + +pub type Task { + Task( + id: Int, + project_id: Int, + title: String, + description: String, + status: String, + assignee: String, + assignees: String, + due_date: String, + ) +} + +pub fn create_user( + db: pog.Connection, + username: String, + password_hash: String, +) { + "insert into app_users (username, password_hash) values ($1, $2) returning id" + |> pog.query + |> pog.parameter(pog.text(username)) + |> pog.parameter(pog.text(password_hash)) + |> pog.returning(decode.field(0, decode.int, decode.success)) + |> pog.execute(db) +} + +pub fn find_user(db: pog.Connection, username: String) { + "select id, username, password_hash from app_users where username = $1" + |> pog.query + |> pog.parameter(pog.text(username)) + |> pog.returning({ + use id <- decode.field(0, decode.int) + use username <- decode.field(1, decode.string) + use password_hash <- decode.field(2, decode.string) + decode.success(User(id:, username:, password_hash:)) + }) + |> pog.execute(db) +} + +pub fn find_username(db: pog.Connection, user_id: Int) { + "select username from app_users where id = $1" + |> pog.query + |> pog.parameter(pog.int(user_id)) + |> pog.returning(decode.field(0, decode.string, decode.success)) + |> pog.execute(db) +} + +pub fn list_projects(db: pog.Connection) { + "select id, name, description from project order by created_at desc, id desc" + |> pog.query + |> pog.returning({ + use id <- decode.field(0, decode.int) + use name <- decode.field(1, decode.string) + use description <- decode.field(2, decode.string) + decode.success(Project(id:, name:, description:)) + }) + |> pog.execute(db) +} + +pub fn create_project(db: pog.Connection, name: String, description: String) { + "insert into project (name, description) values ($1, $2) returning id, name, description" + |> pog.query + |> pog.parameter(pog.text(name)) + |> pog.parameter(pog.text(description)) + |> pog.returning({ + use id <- decode.field(0, decode.int) + use name <- decode.field(1, decode.string) + use description <- decode.field(2, decode.string) + decode.success(Project(id:, name:, description:)) + }) + |> pog.execute(db) +} + +pub fn list_tasks(db: pog.Connection, project_id: Int) { + "select id, project_id, title, description, status, assignee, assignees, coalesce(due_date::text, '') from task where project_id = $1 order by case status when 'doing' then 0 when 'todo' then 1 else 2 end, created_at desc" + |> pog.query + |> pog.parameter(pog.int(project_id)) + |> pog.returning({ + use id <- decode.field(0, decode.int) + use project_id <- decode.field(1, decode.int) + use title <- decode.field(2, decode.string) + use description <- decode.field(3, decode.string) + use status <- decode.field(4, decode.string) + use assignee <- decode.field(5, decode.string) + use assignees <- decode.field(6, decode.string) + use due_date <- decode.field(7, decode.string) + decode.success(Task( + id:, + project_id:, + title:, + description:, + status:, + assignee:, + assignees:, + due_date:, + )) + }) + |> pog.execute(db) +} + +pub fn create_task( + db: pog.Connection, + project_id: Int, + title: String, + description: String, + assignee: String, + assignees: String, + due_date: String, +) { + "insert into task (project_id, title, description, assignee, assignees, due_date) values ($1, $2, $3, $4, $5, nullif($6, '')::date) returning id" + |> pog.query + |> pog.parameter(pog.int(project_id)) + |> pog.parameter(pog.text(title)) + |> pog.parameter(pog.text(description)) + |> pog.parameter(pog.text(assignee)) + |> pog.parameter(pog.text(assignees)) + |> pog.parameter(pog.text(due_date)) + |> pog.returning(decode.field(0, decode.int, decode.success)) + |> pog.execute(db) +} + +pub fn update_task_status(db: pog.Connection, status: String, task_id: Int) { + "update task set status = $1 where id = $2" + |> pog.query + |> pog.parameter(pog.text(status)) + |> pog.parameter(pog.int(task_id)) + |> pog.execute(db) +} + +pub fn create_session(db: pog.Connection, token: String, user_id: Int) { + "insert into session (token, user_id, expires_at) values ($1, $2, now() + interval '30 days')" + |> pog.query + |> pog.parameter(pog.text(token)) + |> pog.parameter(pog.int(user_id)) + |> pog.execute(db) +} + +pub fn find_session(db: pog.Connection, token: String) { + "select user_id from session where token = $1 and expires_at > now()" + |> pog.query + |> pog.parameter(pog.text(token)) + |> pog.returning(decode.field(0, decode.int, decode.success)) + |> pog.execute(db) +} diff --git a/server/src/sql/create_project.sql b/server/src/sql/create_project.sql new file mode 100644 index 0000000..2bd8b13 --- /dev/null +++ b/server/src/sql/create_project.sql @@ -0,0 +1,3 @@ +insert into project (name, description) +values ($1, $2) +returning id, name, description diff --git a/server/src/sql/create_session.sql b/server/src/sql/create_session.sql new file mode 100644 index 0000000..008d7f3 --- /dev/null +++ b/server/src/sql/create_session.sql @@ -0,0 +1,2 @@ +insert into session (token, user_id, expires_at) +values ($1, $2, now() + interval '30 days') diff --git a/server/src/sql/create_task.sql b/server/src/sql/create_task.sql new file mode 100644 index 0000000..b018059 --- /dev/null +++ b/server/src/sql/create_task.sql @@ -0,0 +1,3 @@ +insert into task (project_id, title, description, assignee, assignees, due_date) +values ($1, $2, $3, $4, $5, nullif($6, '')::date) +returning id diff --git a/server/src/sql/create_user.sql b/server/src/sql/create_user.sql new file mode 100644 index 0000000..20947f2 --- /dev/null +++ b/server/src/sql/create_user.sql @@ -0,0 +1,4 @@ +insert into app_user (username, password_hash) +values ($1, $2) +on conflict (username) do nothing +returning id diff --git a/server/src/sql/find_session.sql b/server/src/sql/find_session.sql new file mode 100644 index 0000000..0ce6fba --- /dev/null +++ b/server/src/sql/find_session.sql @@ -0,0 +1,3 @@ +select user_id +from session +where token = $1 and expires_at > now() diff --git a/server/src/sql/find_user.sql b/server/src/sql/find_user.sql new file mode 100644 index 0000000..9c26aa1 --- /dev/null +++ b/server/src/sql/find_user.sql @@ -0,0 +1,3 @@ +select id, username, password_hash +from app_user +where username = $1 diff --git a/server/src/sql/list_projects.sql b/server/src/sql/list_projects.sql new file mode 100644 index 0000000..062fff1 --- /dev/null +++ b/server/src/sql/list_projects.sql @@ -0,0 +1,3 @@ +select id, name, description +from project +order by created_at desc, id desc diff --git a/server/src/sql/list_tasks.sql b/server/src/sql/list_tasks.sql new file mode 100644 index 0000000..68a1290 --- /dev/null +++ b/server/src/sql/list_tasks.sql @@ -0,0 +1,6 @@ +select id, project_id, title, description, status, assignee, assignees, coalesce(due_date::text, '') +from task +where project_id = $1 +order by + case status when 'doing' then 0 when 'todo' then 1 else 2 end, + created_at desc diff --git a/server/src/sql/update_task_status.sql b/server/src/sql/update_task_status.sql new file mode 100644 index 0000000..4ce11a2 --- /dev/null +++ b/server/src/sql/update_task_status.sql @@ -0,0 +1,3 @@ +update task +set status = $1 +where id = $2 diff --git a/server/static/cat.png b/server/static/cat.png new file mode 100644 index 0000000000000000000000000000000000000000..6c4c3ab3334310cfb8e636ebda5fd0a740758922 GIT binary patch literal 65460 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ξHdO_ZHtx#Wa8uqc;UpP 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 s?qv>d)2XD^!$mb2e57 (label in fields) ? fields[label] : this[label]); + return new this.constructor(...properties); + } +} + +class List { + static fromArray(array, tail) { + return toList(array, tail); + } + [Symbol.iterator]() { + return new ListIterator(this); + } + toArray() { + return [...this]; + } + atLeastLength(desired) { + let current = this; + while (desired-- > 0 && current) + current = current.tail; + return current !== undefined; + } + hasLength(desired) { + let current = this; + while (desired-- > 0 && current) + current = current.tail; + return desired === -1 && current instanceof Empty; + } + countLength() { + let current = this; + let length = 0; + while (current) { + current = current.tail; + length++; + } + return length - 1; + } +} +function prepend(element, tail) { + return new NonEmpty(element, tail); +} +function toList(elements, tail) { + let t = tail || List$Empty$const; + for (let i = elements.length - 1;i >= 0; --i) { + t = new NonEmpty(elements[i], t); + } + return t; +} + +class ListIterator { + #current; + constructor(current) { + this.#current = current; + } + next() { + if (this.#current instanceof Empty) { + return { done: true }; + } else { + let { head, tail } = this.#current; + this.#current = tail; + return { value: head, done: false }; + } + } +} + +class Empty extends List { +} +var List$Empty$const = new Empty; +var List$Empty = () => List$Empty$const; +var List$isEmpty = (value) => value instanceof Empty; + +class NonEmpty extends List { + constructor(head, tail) { + super(); + this.head = head; + this.tail = tail; + } +} +var List$NonEmpty = (head, tail) => new NonEmpty(head, tail); +var List$isNonEmpty = (value) => value instanceof NonEmpty; +var List$NonEmpty$first = (value) => value.head; +var List$NonEmpty$rest = (value) => value.tail; + +class BitArray { + bitSize; + byteSize; + bitOffset; + rawBuffer; + constructor(buffer, bitSize, bitOffset) { + if (!(buffer instanceof Uint8Array)) { + throw globalThis.Error("BitArray can only be constructed from a Uint8Array"); + } + this.bitSize = bitSize ?? buffer.length * 8; + this.byteSize = Math.trunc((this.bitSize + 7) / 8); + this.bitOffset = bitOffset ?? 0; + if (this.bitSize < 0) { + throw globalThis.Error(`BitArray bit size is invalid: ${this.bitSize}`); + } + if (this.bitOffset < 0 || this.bitOffset > 7) { + throw globalThis.Error(`BitArray bit offset is invalid: ${this.bitOffset}`); + } + if (buffer.length !== Math.trunc((this.bitOffset + this.bitSize + 7) / 8)) { + throw globalThis.Error("BitArray buffer length is invalid"); + } + this.rawBuffer = buffer; + } + byteAt(index) { + if (index < 0 || index >= this.byteSize) { + return; + } + return bitArrayByteAt(this.rawBuffer, this.bitOffset, index); + } + equals(other) { + if (this.bitSize !== other.bitSize) { + return false; + } + const wholeByteCount = Math.trunc(this.bitSize / 8); + if (this.bitOffset === 0 && other.bitOffset === 0) { + for (let i = 0;i < wholeByteCount; i++) { + if (this.rawBuffer[i] !== other.rawBuffer[i]) { + return false; + } + } + const trailingBitsCount = this.bitSize % 8; + if (trailingBitsCount) { + const unusedLowBitCount = 8 - trailingBitsCount; + if (this.rawBuffer[wholeByteCount] >> unusedLowBitCount !== other.rawBuffer[wholeByteCount] >> unusedLowBitCount) { + return false; + } + } + } else { + for (let i = 0;i < wholeByteCount; i++) { + const a = bitArrayByteAt(this.rawBuffer, this.bitOffset, i); + const b = bitArrayByteAt(other.rawBuffer, other.bitOffset, i); + if (a !== b) { + return false; + } + } + const trailingBitsCount = this.bitSize % 8; + if (trailingBitsCount) { + const a = bitArrayByteAt(this.rawBuffer, this.bitOffset, wholeByteCount); + const b = bitArrayByteAt(other.rawBuffer, other.bitOffset, wholeByteCount); + const unusedLowBitCount = 8 - trailingBitsCount; + if (a >> unusedLowBitCount !== b >> unusedLowBitCount) { + return false; + } + } + } + return true; + } + get buffer() { + if (this.bitOffset !== 0 || this.bitSize % 8 !== 0) { + throw new globalThis.Error("BitArray.buffer does not support unaligned bit arrays"); + } + return this.rawBuffer; + } + get length() { + if (this.bitOffset !== 0 || this.bitSize % 8 !== 0) { + throw new globalThis.Error("BitArray.length does not support unaligned bit arrays"); + } + return this.rawBuffer.length; + } +} +function bitArrayByteAt(buffer, bitOffset, index) { + if (bitOffset === 0) { + return buffer[index] ?? 0; + } else { + const a = buffer[index] << bitOffset & 255; + const b = buffer[index + 1] >> 8 - bitOffset; + return a | b; + } +} + +class UtfCodepoint { + constructor(value) { + this.value = value; + } +} +class Result extends CustomType { + static isResult(data) { + return data instanceof Result; + } +} + +class Ok extends Result { + constructor(value) { + super(); + this[0] = value; + } + isOk() { + return true; + } +} +var Result$Ok = (value) => new Ok(value); +var Result$isOk = (value) => value instanceof Ok; +var Result$Ok$0 = (value) => value[0]; + +class Error2 extends Result { + constructor(detail) { + super(); + this[0] = detail; + } + isOk() { + return false; + } +} +var Result$Error = (detail) => new Error2(detail); +var Result$isError = (value) => value instanceof Error2; +function isEqual(x, y) { + let values = [x, y]; + while (values.length) { + let a = values.pop(); + let b = values.pop(); + if (a === b) + continue; + if (!isObject(a) || !isObject(b)) + return false; + let unequal = !structurallyCompatibleObjects(a, b) || unequalDates(a, b) || unequalBuffers(a, b) || unequalArrays(a, b) || unequalMaps(a, b) || unequalSets(a, b) || unequalRegExps(a, b); + if (unequal) + return false; + const proto = Object.getPrototypeOf(a); + if (proto !== null && typeof proto.equals === "function") { + try { + if (a.equals(b)) + continue; + else + return false; + } catch {} + } + let [keys, get] = getters(a); + const ka = keys(a); + const kb = keys(b); + if (ka.length !== kb.length) + return false; + for (let k of ka) { + values.push(get(a, k), get(b, k)); + } + } + return true; +} +function getters(object) { + if (object instanceof Map) { + return [(x) => x.keys(), (x, y) => x.get(y)]; + } else { + let extra = object instanceof globalThis.Error ? ["message"] : []; + return [(x) => [...extra, ...Object.keys(x)], (x, y) => x[y]]; + } +} +function unequalDates(a, b) { + return a instanceof Date && (a > b || a < b); +} +function unequalBuffers(a, b) { + return !(a instanceof BitArray) && a.buffer instanceof ArrayBuffer && a.BYTES_PER_ELEMENT && !(a.byteLength === b.byteLength && a.every((n, i) => n === b[i])); +} +function unequalArrays(a, b) { + return Array.isArray(a) && a.length !== b.length; +} +function unequalMaps(a, b) { + return a instanceof Map && a.size !== b.size; +} +function unequalSets(a, b) { + return a instanceof Set && (a.size != b.size || [...a].some((e) => !b.has(e))); +} +function unequalRegExps(a, b) { + return a instanceof RegExp && (a.source !== b.source || a.flags !== b.flags); +} +function isObject(a) { + return typeof a === "object" && a !== null; +} +function structurallyCompatibleObjects(a, b) { + if (typeof a !== "object" && typeof b !== "object" && (!a || !b)) + return false; + let nonstructural = [Promise, WeakSet, WeakMap, Function]; + if (nonstructural.some((c) => a instanceof c)) + return false; + return a.constructor === b.constructor; +} +function makeError(variant, file, module, line, fn, message, extra) { + let error = new globalThis.Error(message); + error.gleam_error = variant; + error.file = file; + error.module = module; + error.line = line; + error.function = fn; + error.fn = fn; + for (let k in extra) + error[k] = extra[k]; + return error; +} +// build/dev/javascript/gleam_stdlib/dict.mjs +var referenceMap = /* @__PURE__ */ new WeakMap; +var tempDataView = /* @__PURE__ */ new DataView(/* @__PURE__ */ new ArrayBuffer(8)); +var referenceUID = 0; +function hashByReference(o) { + const known = referenceMap.get(o); + if (known !== undefined) { + return known; + } + const hash = referenceUID++; + if (referenceUID === 2147483647) { + referenceUID = 0; + } + referenceMap.set(o, hash); + return hash; +} +function hashMerge(a, b) { + return a ^ b + 2654435769 + (a << 6) + (a >> 2) | 0; +} +function hashString(s) { + let hash = 0; + const len = s.length; + for (let i = 0;i < len; i++) { + hash = Math.imul(31, hash) + s.charCodeAt(i) | 0; + } + return hash; +} +function hashNumber(n) { + tempDataView.setFloat64(0, n); + const i = tempDataView.getInt32(0); + const j = tempDataView.getInt32(4); + return Math.imul(73244475, i >> 16 ^ i) ^ j; +} +function hashBigInt(n) { + return hashString(n.toString()); +} +function hashObject(o) { + const proto = Object.getPrototypeOf(o); + if (proto !== null && typeof proto.hashCode === "function") { + try { + const code = o.hashCode(o); + if (typeof code === "number") { + return code; + } + } catch {} + } + if (o instanceof Promise || o instanceof WeakSet || o instanceof WeakMap) { + return hashByReference(o); + } + if (o instanceof Date) { + return hashNumber(o.getTime()); + } + let h = 0; + if (o instanceof ArrayBuffer) { + o = new Uint8Array(o); + } + if (Array.isArray(o) || o instanceof Uint8Array) { + for (let i = 0;i < o.length; i++) { + h = Math.imul(31, h) + getHash(o[i]) | 0; + } + } else if (o instanceof Set) { + o.forEach((v) => { + h = h + getHash(v) | 0; + }); + } else if (o instanceof Map) { + o.forEach((v, k) => { + h = h + hashMerge(getHash(v), getHash(k)) | 0; + }); + } else { + const keys = Object.keys(o); + for (let i = 0;i < keys.length; i++) { + const k = keys[i]; + const v = o[k]; + h = h + hashMerge(getHash(v), hashString(k)) | 0; + } + } + return h; +} +function getHash(u) { + if (u === null) + return 1108378658; + if (u === undefined) + return 1108378659; + if (u === true) + return 1108378657; + if (u === false) + return 1108378656; + switch (typeof u) { + case "number": + return hashNumber(u); + case "string": + return hashString(u); + case "bigint": + return hashBigInt(u); + case "object": + return hashObject(u); + case "symbol": + return hashByReference(u); + case "function": + return hashByReference(u); + default: + return 0; + } +} + +class Dict { + constructor(size, root) { + this.size = size; + this.root = root; + } +} +var bits = 5; +var mask = (1 << bits) - 1; +var noElementMarker = Symbol(); + +class Node { + constructor(generation, datamap, nodemap, data) { + this.datamap = datamap; + this.nodemap = nodemap; + this.data = data; + this.generation = generation; + } + equals(other) { + if (this === other) + return true; + if (!(other instanceof Node)) + return false; + if (this.datamap !== other.datamap || this.nodemap !== other.nodemap) { + return false; + } + const leftData = this.data; + const rightData = other.data; + if (leftData.length !== rightData.length) + return false; + if (this.datamap === 0 && this.nodemap === 0) { + return this.#equalsOverflowEntries(rightData); + } + const edgesStart = leftData.length - popcount(this.nodemap); + for (let i = 0;i < edgesStart; i += 2) { + if (!isEqual(leftData[i], rightData[i]) || !isEqual(leftData[i + 1], rightData[i + 1])) { + return false; + } + } + for (let i = edgesStart;i < leftData.length; ++i) { + if (!leftData[i].equals(rightData[i])) + return false; + } + return true; + } + #equalsOverflowEntries(otherData) { + const data = this.data; + entries: + for (let i = 0;i < data.length; i += 2) { + for (let j = 0;j < otherData.length; j += 2) { + if (isEqual(data[i], otherData[j])) { + if (!isEqual(data[i + 1], otherData[j + 1])) + return false; + continue entries; + } + } + return false; + } + return true; + } + hashCode() { + const data = this.data; + const edgesStart = data.length - popcount(this.nodemap); + let hash = 0; + for (let i = 0;i < edgesStart; i += 2) { + hash = hash + hashMerge(getHash(data[i + 1]), getHash(data[i])) | 0; + } + for (let i = edgesStart;i < data.length; ++i) { + hash = hash + data[i].hashCode() | 0; + } + return hash; + } +} +var emptyNode = /* @__PURE__ */ newNode(0); +var emptyDict = /* @__PURE__ */ new Dict(0, emptyNode); +var errorNil = /* @__PURE__ */ Result$Error(undefined); +function newNode(generation) { + return new Node(generation, 0, 0, []); +} +function copyNode(node, generation) { + if (node.generation === generation) { + return node; + } + const newData = node.data.slice(0); + return new Node(generation, node.datamap, node.nodemap, newData); +} +function copyAndSet(node, generation, idx, val) { + if (node.data[idx] === val) { + return node; + } + node = copyNode(node, generation); + node.data[idx] = val; + return node; +} +function copyAndInsertPair(node, generation, bit, idx, key, val) { + const data = node.data; + const length = data.length; + const newData = new Array(length + 2); + let readIndex = 0; + let writeIndex = 0; + while (readIndex < idx) + newData[writeIndex++] = data[readIndex++]; + newData[writeIndex++] = key; + newData[writeIndex++] = val; + while (readIndex < length) + newData[writeIndex++] = data[readIndex++]; + return new Node(generation, node.datamap | bit, node.nodemap, newData); +} +function copyAndRemovePair(node, generation, bit, idx) { + node = copyNode(node, generation); + const data = node.data; + const length = data.length; + for (let w = idx, r = idx + 2;r < length; ++r, ++w) { + data[w] = data[r]; + } + data.pop(); + data.pop(); + node.datamap ^= bit; + return node; +} +function make() { + return emptyDict; +} +function get(dict, key) { + const result = lookup(dict.root, key, getHash(key)); + return result !== noElementMarker ? Result$Ok(result) : errorNil; +} +function lookup(node, key, hash) { + for (let shift = 0;shift < 32; shift += bits) { + const data = node.data; + const bit = hashbit(hash, shift); + if (node.nodemap & bit) { + node = data[data.length - 1 - index(node.nodemap, bit)]; + } else if (node.datamap & bit) { + const dataidx = Math.imul(index(node.datamap, bit), 2); + return isEqual(key, data[dataidx]) ? data[dataidx + 1] : noElementMarker; + } else { + return noElementMarker; + } + } + const overflow = node.data; + for (let i = 0;i < overflow.length; i += 2) { + if (isEqual(key, overflow[i])) { + return overflow[i + 1]; + } + } + return noElementMarker; +} +function toTransient(dict) { + return { + generation: nextGeneration(dict), + root: dict.root, + size: dict.size, + dict + }; +} +function fromTransient(transient) { + if (transient.root === transient.dict.root) { + return transient.dict; + } + return new Dict(transient.size, transient.root); +} +function nextGeneration(dict) { + const root = dict.root; + if (root.generation < Number.MAX_SAFE_INTEGER) { + return root.generation + 1; + } + const queue = [root]; + while (queue.length) { + const node = queue.pop(); + node.generation = 0; + const nodeStart = node.data.length - popcount(node.nodemap); + for (let i = nodeStart;i < node.data.length; ++i) { + queue.push(node.data[i]); + } + } + return 1; +} +var globalTransient = /* @__PURE__ */ toTransient(emptyDict); +function insert(dict, key, value) { + globalTransient.generation = nextGeneration(dict); + globalTransient.size = dict.size; + const hash = getHash(key); + const root = insertIntoNode(globalTransient, dict.root, key, value, hash, 0); + if (root === dict.root) { + return dict; + } + return new Dict(globalTransient.size, root); +} +function insertIntoNode(transient, node, key, value, hash, shift) { + const data = node.data; + const generation = transient.generation; + if (shift > 32) { + for (let i = 0;i < data.length; i += 2) { + if (isEqual(key, data[i])) { + return copyAndSet(node, generation, i + 1, value); + } + } + transient.size += 1; + return copyAndInsertPair(node, generation, 0, data.length, key, value); + } + const bit = hashbit(hash, shift); + if (node.nodemap & bit) { + const nodeidx2 = data.length - 1 - index(node.nodemap, bit); + let child2 = data[nodeidx2]; + child2 = insertIntoNode(transient, child2, key, value, hash, shift + bits); + return copyAndSet(node, generation, nodeidx2, child2); + } + const dataidx = Math.imul(index(node.datamap, bit), 2); + if ((node.datamap & bit) === 0) { + transient.size += 1; + return copyAndInsertPair(node, generation, bit, dataidx, key, value); + } + if (isEqual(key, data[dataidx])) { + return copyAndSet(node, generation, dataidx + 1, value); + } + const childShift = shift + bits; + let child = emptyNode; + child = insertIntoNode(transient, child, key, value, hash, childShift); + const key2 = data[dataidx]; + const value2 = data[dataidx + 1]; + const hash2 = getHash(key2); + child = insertIntoNode(transient, child, key2, value2, hash2, childShift); + transient.size -= 1; + const length = data.length; + const nodeidx = length - 1 - index(node.nodemap, bit); + const newData = new Array(length - 1); + let readIndex = 0; + let writeIndex = 0; + while (readIndex < dataidx) + newData[writeIndex++] = data[readIndex++]; + readIndex += 2; + while (readIndex <= nodeidx) + newData[writeIndex++] = data[readIndex++]; + newData[writeIndex++] = child; + while (readIndex < length) + newData[writeIndex++] = data[readIndex++]; + return new Node(generation, node.datamap ^ bit, node.nodemap | bit, newData); +} +function destructiveTransientDelete(key, transient) { + const hash = getHash(key); + transient.root = deleteFromNode(transient, transient.root, key, hash, 0); + return transient; +} +function deleteFromNode(transient, node, key, hash, shift) { + const data = node.data; + const generation = transient.generation; + if (shift > 32) { + for (let i = 0;i < data.length; i += 2) { + if (isEqual(key, data[i])) { + transient.size -= 1; + return copyAndRemovePair(node, generation, 0, i); + } + } + return node; + } + const bit = hashbit(hash, shift); + const dataidx = Math.imul(index(node.datamap, bit), 2); + if ((node.nodemap & bit) !== 0) { + const nodeidx = data.length - 1 - index(node.nodemap, bit); + let child = data[nodeidx]; + child = deleteFromNode(transient, child, key, hash, shift + bits); + if (child.nodemap !== 0 || child.data.length > 2) { + return copyAndSet(node, generation, nodeidx, child); + } + const length = data.length; + const newData = new Array(length + 1); + let readIndex = 0; + let writeIndex = 0; + while (readIndex < dataidx) + newData[writeIndex++] = data[readIndex++]; + newData[writeIndex++] = child.data[0]; + newData[writeIndex++] = child.data[1]; + while (readIndex < nodeidx) + newData[writeIndex++] = data[readIndex++]; + readIndex++; + while (readIndex < length) + newData[writeIndex++] = data[readIndex++]; + return new Node(generation, node.datamap | bit, node.nodemap ^ bit, newData); + } + if ((node.datamap & bit) === 0 || !isEqual(key, data[dataidx])) { + return node; + } + transient.size -= 1; + return copyAndRemovePair(node, generation, bit, dataidx); +} +function fold(dict, state, fun) { + const queue = [dict.root]; + while (queue.length) { + const node = queue.pop(); + const data = node.data; + const edgesStart = data.length - popcount(node.nodemap); + for (let i = 0;i < edgesStart; i += 2) { + state = fun(state, data[i], data[i + 1]); + } + for (let i = edgesStart;i < data.length; ++i) { + queue.push(data[i]); + } + } + return state; +} +function popcount(n) { + n -= n >>> 1 & 1431655765; + n = (n & 858993459) + (n >>> 2 & 858993459); + return Math.imul(n + (n >>> 4) & 252645135, 16843009) >>> 24; +} +function index(bitmap, bit) { + return popcount(bitmap & bit - 1); +} +function hashbit(hash, shift) { + return 1 << (hash >>> shift & mask); +} + +// build/dev/javascript/gleam_stdlib/gleam/option.mjs +class Some extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } +} +var Option$isSome = (value) => value instanceof Some; +var Option$Some$0 = (value) => value[0]; + +class None extends CustomType { +} +var Option$None$const = new None; +function to_result(option, e) { + if (option instanceof Some) { + let a = option[0]; + return new Ok(a); + } else { + return new Error2(e); + } +} +function unwrap(option, default$) { + if (option instanceof Some) { + let x = option[0]; + return x; + } else { + return default$; + } +} + +// build/dev/javascript/gleam_stdlib/gleam/dict.mjs +function keys(dict) { + return fold(dict, List$Empty$const, (acc, key, _) => { + return prepend(key, acc); + }); +} +function delete$(dict, key) { + let _pipe = toTransient(dict); + let _pipe$1 = ((_capture) => { + return destructiveTransientDelete(key, _capture); + })(_pipe); + return fromTransient(_pipe$1); +} + +// build/dev/javascript/gleam_stdlib/gleam/order.mjs +class Lt extends CustomType { +} +var Order$Lt$const = new Lt; +var Order$Lt = () => Order$Lt$const; +class Eq extends CustomType { +} +var Order$Eq$const = new Eq; +var Order$Eq = () => Order$Eq$const; +class Gt extends CustomType { +} +var Order$Gt$const = new Gt; +var Order$Gt = () => Order$Gt$const; + +// build/dev/javascript/gleam_stdlib/gleam/list.mjs +class Ascending extends CustomType { +} +var Sorting$Ascending$const = new Ascending; + +class Descending extends CustomType { +} +var Sorting$Descending$const = new Descending; +function reverse_and_prepend(loop$prefix, loop$suffix) { + while (true) { + let prefix = loop$prefix; + let suffix = loop$suffix; + if (prefix instanceof Empty) { + return suffix; + } else { + let first$1 = prefix.head; + let rest$1 = prefix.tail; + loop$prefix = rest$1; + loop$suffix = prepend(first$1, suffix); + } + } +} +function reverse(list) { + return reverse_and_prepend(list, List$Empty$const); +} +function filter_map_loop(loop$list, loop$fun, loop$acc) { + while (true) { + let list = loop$list; + let fun = loop$fun; + let acc = loop$acc; + if (list instanceof Empty) { + return reverse(acc); + } else { + let first$1 = list.head; + let rest$1 = list.tail; + let _block; + let $ = fun(first$1); + if ($ instanceof Ok) { + let first$2 = $[0]; + _block = prepend(first$2, acc); + } else { + _block = acc; + } + let new_acc = _block; + loop$list = rest$1; + loop$fun = fun; + loop$acc = new_acc; + } + } +} +function filter_map(list, fun) { + return filter_map_loop(list, fun, List$Empty$const); +} +function map_loop(loop$list, loop$fun, loop$acc) { + while (true) { + let list = loop$list; + let fun = loop$fun; + let acc = loop$acc; + if (list instanceof Empty) { + return reverse(acc); + } else { + let first$1 = list.head; + let rest$1 = list.tail; + loop$list = rest$1; + loop$fun = fun; + loop$acc = prepend(fun(first$1), acc); + } + } +} +function map2(list, fun) { + return map_loop(list, fun, List$Empty$const); +} +function append_loop(loop$first, loop$second) { + while (true) { + let first = loop$first; + let second = loop$second; + if (first instanceof Empty) { + return second; + } else { + let first$1 = first.head; + let rest$1 = first.tail; + loop$first = rest$1; + loop$second = prepend(first$1, second); + } + } +} +function append(first, second) { + return append_loop(reverse(first), second); +} +function prepend2(list, item) { + return prepend(item, list); +} +function fold2(loop$list, loop$initial, loop$fun) { + while (true) { + let list = loop$list; + let initial = loop$initial; + let fun = loop$fun; + if (list instanceof Empty) { + return initial; + } else { + let first$1 = list.head; + let rest$1 = list.tail; + loop$list = rest$1; + loop$initial = fun(initial, first$1); + loop$fun = fun; + } + } +} +function find_map(loop$list, loop$fun) { + while (true) { + let list = loop$list; + let fun = loop$fun; + if (list instanceof Empty) { + return new Error2(undefined); + } else { + let first$1 = list.head; + let rest$1 = list.tail; + let $ = fun(first$1); + if ($ instanceof Ok) { + return $; + } else { + loop$list = rest$1; + loop$fun = fun; + } + } + } +} +function merge_descendings(loop$list1, loop$list2, loop$compare, loop$acc) { + while (true) { + let list1 = loop$list1; + let list2 = loop$list2; + let compare2 = loop$compare; + let acc = loop$acc; + if (list1 instanceof Empty) { + let list = list2; + return reverse_and_prepend(list, acc); + } else if (list2 instanceof Empty) { + let list = list1; + return reverse_and_prepend(list, acc); + } else { + let first1 = list1.head; + let rest1 = list1.tail; + let first2 = list2.head; + let rest2 = list2.tail; + let $ = compare2(first1, first2); + if ($ instanceof Lt) { + loop$list1 = list1; + loop$list2 = rest2; + loop$compare = compare2; + loop$acc = prepend(first2, acc); + } else if ($ instanceof Eq) { + loop$list1 = rest1; + loop$list2 = list2; + loop$compare = compare2; + loop$acc = prepend(first1, acc); + } else { + loop$list1 = rest1; + loop$list2 = list2; + loop$compare = compare2; + loop$acc = prepend(first1, acc); + } + } + } +} +function merge_descending_pairs(loop$sequences, loop$compare, loop$acc) { + while (true) { + let sequences = loop$sequences; + let compare2 = loop$compare; + let acc = loop$acc; + if (sequences instanceof Empty) { + return reverse(acc); + } else { + let $ = sequences.tail; + if ($ instanceof Empty) { + let sequence = sequences.head; + return reverse(prepend(reverse(sequence), acc)); + } else { + let descending1 = sequences.head; + let descending2 = $.head; + let rest$1 = $.tail; + let ascending = merge_descendings(descending1, descending2, compare2, List$Empty$const); + loop$sequences = rest$1; + loop$compare = compare2; + loop$acc = prepend(ascending, acc); + } + } + } +} +function merge_ascendings(loop$list1, loop$list2, loop$compare, loop$acc) { + while (true) { + let list1 = loop$list1; + let list2 = loop$list2; + let compare2 = loop$compare; + let acc = loop$acc; + if (list1 instanceof Empty) { + let list = list2; + return reverse_and_prepend(list, acc); + } else if (list2 instanceof Empty) { + let list = list1; + return reverse_and_prepend(list, acc); + } else { + let first1 = list1.head; + let rest1 = list1.tail; + let first2 = list2.head; + let rest2 = list2.tail; + let $ = compare2(first1, first2); + if ($ instanceof Lt) { + loop$list1 = rest1; + loop$list2 = list2; + loop$compare = compare2; + loop$acc = prepend(first1, acc); + } else if ($ instanceof Eq) { + loop$list1 = list1; + loop$list2 = rest2; + loop$compare = compare2; + loop$acc = prepend(first2, acc); + } else { + loop$list1 = list1; + loop$list2 = rest2; + loop$compare = compare2; + loop$acc = prepend(first2, acc); + } + } + } +} +function merge_ascending_pairs(loop$sequences, loop$compare, loop$acc) { + while (true) { + let sequences = loop$sequences; + let compare2 = loop$compare; + let acc = loop$acc; + if (sequences instanceof Empty) { + return reverse(acc); + } else { + let $ = sequences.tail; + if ($ instanceof Empty) { + let sequence = sequences.head; + return reverse(prepend(reverse(sequence), acc)); + } else { + let ascending1 = sequences.head; + let ascending2 = $.head; + let rest$1 = $.tail; + let descending = merge_ascendings(ascending1, ascending2, compare2, List$Empty$const); + loop$sequences = rest$1; + loop$compare = compare2; + loop$acc = prepend(descending, acc); + } + } + } +} +function merge_all(loop$sequences, loop$direction, loop$compare) { + while (true) { + let sequences = loop$sequences; + let direction = loop$direction; + let compare2 = loop$compare; + if (sequences instanceof Empty) { + return sequences; + } else if (direction instanceof Ascending) { + let $ = sequences.tail; + if ($ instanceof Empty) { + let sequence = sequences.head; + return sequence; + } else { + let sequences$1 = merge_ascending_pairs(sequences, compare2, List$Empty$const); + loop$sequences = sequences$1; + loop$direction = Sorting$Descending$const; + loop$compare = compare2; + } + } else { + let $ = sequences.tail; + if ($ instanceof Empty) { + let sequence = sequences.head; + return reverse(sequence); + } else { + let sequences$1 = merge_descending_pairs(sequences, compare2, List$Empty$const); + loop$sequences = sequences$1; + loop$direction = Sorting$Ascending$const; + loop$compare = compare2; + } + } + } +} +function sequences(loop$list, loop$compare, loop$growing, loop$direction, loop$prev, loop$acc) { + while (true) { + let list = loop$list; + let compare2 = loop$compare; + let growing = loop$growing; + let direction = loop$direction; + let prev = loop$prev; + let acc = loop$acc; + let growing$1 = prepend(prev, growing); + if (list instanceof Empty) { + if (direction instanceof Ascending) { + return prepend(reverse(growing$1), acc); + } else { + return prepend(growing$1, acc); + } + } else { + let new$1 = list.head; + let rest$1 = list.tail; + let $ = compare2(prev, new$1); + if (direction instanceof Ascending) { + if ($ instanceof Lt) { + loop$list = rest$1; + loop$compare = compare2; + loop$growing = growing$1; + loop$direction = direction; + loop$prev = new$1; + loop$acc = acc; + } else if ($ instanceof Eq) { + loop$list = rest$1; + loop$compare = compare2; + loop$growing = growing$1; + loop$direction = direction; + loop$prev = new$1; + loop$acc = acc; + } else { + let _block; + if (direction instanceof Ascending) { + _block = prepend(reverse(growing$1), acc); + } else { + _block = prepend(growing$1, acc); + } + let acc$1 = _block; + if (rest$1 instanceof Empty) { + return prepend(toList([new$1]), acc$1); + } else { + let next = rest$1.head; + let rest$2 = rest$1.tail; + let _block$1; + let $1 = compare2(new$1, next); + if ($1 instanceof Lt) { + _block$1 = Sorting$Ascending$const; + } else if ($1 instanceof Eq) { + _block$1 = Sorting$Ascending$const; + } else { + _block$1 = Sorting$Descending$const; + } + let direction$1 = _block$1; + loop$list = rest$2; + loop$compare = compare2; + loop$growing = toList([new$1]); + loop$direction = direction$1; + loop$prev = next; + loop$acc = acc$1; + } + } + } else if ($ instanceof Lt) { + let _block; + if (direction instanceof Ascending) { + _block = prepend(reverse(growing$1), acc); + } else { + _block = prepend(growing$1, acc); + } + let acc$1 = _block; + if (rest$1 instanceof Empty) { + return prepend(toList([new$1]), acc$1); + } else { + let next = rest$1.head; + let rest$2 = rest$1.tail; + let _block$1; + let $1 = compare2(new$1, next); + if ($1 instanceof Lt) { + _block$1 = Sorting$Ascending$const; + } else if ($1 instanceof Eq) { + _block$1 = Sorting$Ascending$const; + } else { + _block$1 = Sorting$Descending$const; + } + let direction$1 = _block$1; + loop$list = rest$2; + loop$compare = compare2; + loop$growing = toList([new$1]); + loop$direction = direction$1; + loop$prev = next; + loop$acc = acc$1; + } + } else if ($ instanceof Eq) { + let _block; + if (direction instanceof Ascending) { + _block = prepend(reverse(growing$1), acc); + } else { + _block = prepend(growing$1, acc); + } + let acc$1 = _block; + if (rest$1 instanceof Empty) { + return prepend(toList([new$1]), acc$1); + } else { + let next = rest$1.head; + let rest$2 = rest$1.tail; + let _block$1; + let $1 = compare2(new$1, next); + if ($1 instanceof Lt) { + _block$1 = Sorting$Ascending$const; + } else if ($1 instanceof Eq) { + _block$1 = Sorting$Ascending$const; + } else { + _block$1 = Sorting$Descending$const; + } + let direction$1 = _block$1; + loop$list = rest$2; + loop$compare = compare2; + loop$growing = toList([new$1]); + loop$direction = direction$1; + loop$prev = next; + loop$acc = acc$1; + } + } else { + loop$list = rest$1; + loop$compare = compare2; + loop$growing = growing$1; + loop$direction = direction; + loop$prev = new$1; + loop$acc = acc; + } + } + } +} +function sort(list, compare2) { + if (list instanceof Empty) { + return list; + } else { + let $ = list.tail; + if ($ instanceof Empty) { + return list; + } else { + let x = list.head; + let y = $.head; + let rest$1 = $.tail; + let _block; + let $1 = compare2(x, y); + if ($1 instanceof Lt) { + _block = Sorting$Ascending$const; + } else if ($1 instanceof Eq) { + _block = Sorting$Ascending$const; + } else { + _block = Sorting$Descending$const; + } + let direction = _block; + let sequences$1 = sequences(rest$1, compare2, toList([x]), direction, y, List$Empty$const); + return merge_all(sequences$1, Sorting$Ascending$const, compare2); + } + } +} +function key_find(keyword_list, desired_key) { + return find_map(keyword_list, (keyword) => { + let key = keyword[0]; + let value = keyword[1]; + let $ = isEqual(key, desired_key); + if ($) { + return new Ok(value); + } else { + return new Error2(undefined); + } + }); +} +function key_set_loop(loop$list, loop$key, loop$value, loop$inspected) { + while (true) { + let list = loop$list; + let key = loop$key; + let value = loop$value; + let inspected = loop$inspected; + if (list instanceof Empty) { + return reverse(prepend([key, value], inspected)); + } else { + let k = list.head[0]; + if (isEqual(k, key)) { + let rest$1 = list.tail; + return reverse_and_prepend(inspected, prepend([k, value], rest$1)); + } else { + let first$1 = list.head; + let rest$1 = list.tail; + loop$list = rest$1; + loop$key = key; + loop$value = value; + loop$inspected = prepend(first$1, inspected); + } + } + } +} +function key_set(list, key, value) { + return key_set_loop(list, key, value, List$Empty$const); +} +function each(loop$list, loop$f) { + while (true) { + let list = loop$list; + let f = loop$f; + if (list instanceof Empty) { + return; + } else { + let first$1 = list.head; + let rest$1 = list.tail; + f(first$1); + loop$list = rest$1; + loop$f = f; + } + } +} + +// build/dev/javascript/gleam_stdlib/gleam/string_tree.mjs +class All extends CustomType { +} +var Direction$All$const = new All; + +// build/dev/javascript/gleam_stdlib/gleam/string.mjs +class Leading extends CustomType { +} +var Direction$Leading$const = new Leading; + +class Trailing extends CustomType { +} +var Direction$Trailing$const = new Trailing; +function split2(x, substring) { + if (substring === "") { + return graphemes(x); + } else { + let _pipe = x; + let _pipe$1 = identity(_pipe); + let _pipe$2 = split(_pipe$1, substring); + return map2(_pipe$2, identity); + } +} +function concat_loop(loop$strings, loop$accumulator) { + while (true) { + let strings = loop$strings; + let accumulator = loop$accumulator; + if (strings instanceof Empty) { + return accumulator; + } else { + let string2 = strings.head; + let strings$1 = strings.tail; + loop$strings = strings$1; + loop$accumulator = accumulator + string2; + } + } +} +function concat2(strings) { + return concat_loop(strings, ""); +} + +// build/dev/javascript/gleam_stdlib/gleam/dynamic/decode.mjs +class DecodeError extends CustomType { + constructor(expected, found, path) { + super(); + this.expected = expected; + this.found = found; + this.path = path; + } +} +var DecodeError$DecodeError = (expected, found, path) => new DecodeError(expected, found, path); +class Decoder extends CustomType { + constructor(function$) { + super(); + this.function = function$; + } +} +var float2 = /* @__PURE__ */ new Decoder(decode_float); +var int2 = /* @__PURE__ */ new Decoder(decode_int); +var string3 = /* @__PURE__ */ new Decoder(decode_string); +function run(data, decoder) { + let $ = decoder.function(data); + let maybe_invalid_data = $[0]; + let errors = $[1]; + if (errors instanceof Empty) { + return new Ok(maybe_invalid_data); + } else { + return new Error2(errors); + } +} +function run_dynamic_function(data, name, f) { + let $ = f(data); + if ($ instanceof Ok) { + let data$1 = $[0]; + return [data$1, List$Empty$const]; + } else { + let placeholder = $[0]; + return [ + placeholder, + toList([new DecodeError(name, classify_dynamic(data), List$Empty$const)]) + ]; + } +} +function decode_float(data) { + return run_dynamic_function(data, "Float", float); +} +function map3(decoder, transformer) { + return new Decoder((d) => { + let $ = decoder.function(d); + let data = $[0]; + let errors = $[1]; + return [transformer(data), errors]; + }); +} +function decode_int(data) { + return run_dynamic_function(data, "Int", int); +} +function decode_string(data) { + return run_dynamic_function(data, "String", string2); +} +function run_decoders(loop$data, loop$failure, loop$decoders) { + while (true) { + let data = loop$data; + let failure = loop$failure; + let decoders = loop$decoders; + if (decoders instanceof Empty) { + return failure; + } else { + let decoder = decoders.head; + let decoders$1 = decoders.tail; + let $ = decoder.function(data); + let layer = $; + let errors = $[1]; + if (errors instanceof Empty) { + return layer; + } else { + loop$data = data; + loop$failure = failure; + loop$decoders = decoders$1; + } + } + } +} +function one_of(first, alternatives) { + return new Decoder((dynamic_data) => { + let $ = first.function(dynamic_data); + let layer = $; + let errors = $[1]; + if (errors instanceof Empty) { + return layer; + } else { + return run_decoders(dynamic_data, layer, alternatives); + } + }); +} +function path_segment_to_string(key) { + let decoder = one_of(string3, toList([ + (() => { + let _pipe = int2; + return map3(_pipe, to_string); + })(), + (() => { + let _pipe = float2; + return map3(_pipe, float_to_string); + })() + ])); + let $ = run(key, decoder); + if ($ instanceof Ok) { + let key$1 = $[0]; + return key$1; + } else { + return "<" + classify_dynamic(key) + ">"; + } +} +function push_path(layer, path) { + let path$1 = map2(path, (key) => { + let _pipe = key; + let _pipe$1 = identity(_pipe); + return path_segment_to_string(_pipe$1); + }); + let errors = map2(layer[1], (error) => { + return new DecodeError(error.expected, error.found, append(path$1, error.path)); + }); + return [layer[0], errors]; +} +function list2(inner) { + return new Decoder((data) => { + return list(data, inner.function, (p, k) => { + return push_path(p, toList([k])); + }, 0, List$Empty$const); + }); +} +function index3(loop$path, loop$position, loop$inner, loop$data, loop$handle_miss) { + while (true) { + let path = loop$path; + let position = loop$position; + let inner = loop$inner; + let data = loop$data; + let handle_miss = loop$handle_miss; + if (path instanceof Empty) { + let _pipe = data; + let _pipe$1 = inner(_pipe); + return push_path(_pipe$1, reverse(position)); + } else { + let key = path.head; + let path$1 = path.tail; + let $ = index2(data, key); + if ($ instanceof Ok) { + let $1 = $[0]; + if ($1 instanceof Some) { + let data$1 = $1[0]; + loop$path = path$1; + loop$position = prepend(key, position); + loop$inner = inner; + loop$data = data$1; + loop$handle_miss = handle_miss; + } else { + return handle_miss(data, prepend(key, position)); + } + } else { + let kind = $[0]; + let $1 = inner(data); + let default$ = $1[0]; + let _pipe = [ + default$, + toList([ + new DecodeError(kind, classify_dynamic(data), List$Empty$const) + ]) + ]; + return push_path(_pipe, reverse(position)); + } + } + } +} +function subfield(field_path, field_decoder, next) { + return new Decoder((data) => { + let $ = index3(field_path, List$Empty$const, field_decoder.function, data, (data2, position) => { + let $12 = field_decoder.function(data2); + let default$ = $12[0]; + let _pipe = [ + default$, + toList([new DecodeError("Field", "Nothing", List$Empty$const)]) + ]; + return push_path(_pipe, reverse(position)); + }); + let out = $[0]; + let errors1 = $[1]; + let $1 = next(out).function(data); + let out$1 = $1[0]; + let errors2 = $1[1]; + return [out$1, append(errors1, errors2)]; + }); +} +function success(data) { + return new Decoder((_) => { + return [data, List$Empty$const]; + }); +} +function field(field_name, field_decoder, next) { + return subfield(toList([field_name]), field_decoder, next); +} + +// build/dev/javascript/gleam_stdlib/gleam_stdlib.mjs +function identity(x) { + return x; +} +function to_string(term) { + return term.toString(); +} +function graphemes(string4) { + const iterator = graphemes_iterator(string4); + if (iterator) { + return arrayToList(Array.from(iterator).map((item) => item.segment)); + } else { + return arrayToList(string4.match(/./gsu)); + } +} +var segmenter = undefined; +function graphemes_iterator(string4) { + if (globalThis.Intl && Intl.Segmenter) { + segmenter ||= new Intl.Segmenter; + return segmenter.segment(string4)[Symbol.iterator](); + } +} +function pop_codeunit(str) { + return [str.charCodeAt(0) | 0, str.slice(1)]; +} +function lowercase(string4) { + return string4.toLowerCase(); +} +function split(xs, pattern) { + return arrayToList(xs.split(pattern)); +} +function string_codeunit_slice(str, from2, length2) { + return str.slice(from2, from2 + length2); +} +function starts_with(haystack, needle) { + return haystack.startsWith(needle); +} +var unicode_whitespaces = [ + " ", + "\t", + ` +`, + "\v", + "\f", + "\r", + "…", + "\u2028", + "\u2029" +].join(""); +var trim_start_regex = /* @__PURE__ */ new RegExp(`^[${unicode_whitespaces}]*`); +var trim_end_regex = /* @__PURE__ */ new RegExp(`[${unicode_whitespaces}]*$`); +function classify_dynamic(data) { + if (typeof data === "string") { + return "String"; + } else if (typeof data === "boolean") { + return "Bool"; + } else if (isResult(data)) { + return "Result"; + } else if (isList(data)) { + return "List"; + } else if (data instanceof BitArray) { + return "BitArray"; + } else if (data instanceof Dict) { + return "Dict"; + } else if (Number.isInteger(data)) { + return "Int"; + } else if (Array.isArray(data)) { + return `Array`; + } else if (typeof data === "number") { + return "Float"; + } else if (data === null) { + return "Nil"; + } else if (data === undefined) { + return "Nil"; + } else { + const type = typeof data; + return type.charAt(0).toUpperCase() + type.slice(1); + } +} +var MIN_I32 = -(2 ** 31); +var MAX_I32 = 2 ** 31 - 1; +var U32 = 2 ** 32; +var MAX_SAFE = Number.MAX_SAFE_INTEGER; +var MIN_SAFE = Number.MIN_SAFE_INTEGER; +function float_to_string(float3) { + const string4 = float3.toString().replace("+", ""); + if (string4.indexOf(".") >= 0) { + return string4; + } else { + const index4 = string4.indexOf("e"); + if (index4 >= 0) { + return string4.slice(0, index4) + ".0" + string4.slice(index4); + } else { + return string4 + ".0"; + } + } +} + +class Inspector { + #references = new Set; + inspect(v) { + const t = typeof v; + if (v === true) + return "True"; + if (v === false) + return "False"; + if (v === null) + return "//js(null)"; + if (v === undefined) + return "Nil"; + if (t === "string") + return this.#string(v); + if (t === "bigint" || Number.isInteger(v)) + return v.toString(); + if (t === "number") + return float_to_string(v); + if (v instanceof UtfCodepoint) + return this.#utfCodepoint(v); + if (v instanceof BitArray) + return this.#bit_array(v); + if (v instanceof RegExp) + return `//js(${v})`; + if (v instanceof Date) + return `//js(Date("${v.toISOString()}"))`; + if (v instanceof globalThis.Error) + return `//js(${v.toString()})`; + if (v instanceof Function) { + const args = []; + for (const i of Array(v.length).keys()) + args.push(String.fromCharCode(i + 97)); + return `//fn(${args.join(", ")}) { ... }`; + } + if (this.#references.size === this.#references.add(v).size) { + return "//js(circular reference)"; + } + let printed; + if (Array.isArray(v)) { + printed = `#(${v.map((v2) => this.inspect(v2)).join(", ")})`; + } else if (isList(v)) { + printed = this.#list(v); + } else if (v instanceof CustomType) { + printed = this.#customType(v); + } else if (v instanceof Dict) { + printed = this.#dict(v); + } else if (v instanceof Set) { + return `//js(Set(${[...v].map((v2) => this.inspect(v2)).join(", ")}))`; + } else { + printed = this.#object(v); + } + this.#references.delete(v); + return printed; + } + #object(v) { + const name = Object.getPrototypeOf(v)?.constructor?.name || "Object"; + const props = []; + for (const k of Object.keys(v)) { + props.push(`${this.inspect(k)}: ${this.inspect(v[k])}`); + } + const body = props.length ? " " + props.join(", ") + " " : ""; + const head = name === "Object" ? "" : name + " "; + return `//js(${head}{${body}})`; + } + #dict(map4) { + let body = "dict.from_list(["; + let first = true; + body = fold(map4, body, (body2, key, value) => { + if (!first) + body2 = body2 + ", "; + first = false; + return body2 + "#(" + this.inspect(key) + ", " + this.inspect(value) + ")"; + }); + return body + "])"; + } + #customType(record) { + const props = Object.keys(record).map((label) => { + const value = this.inspect(record[label]); + return isNaN(parseInt(label)) ? `${label}: ${value}` : value; + }).join(", "); + return props ? `${record.constructor.name}(${props})` : record.constructor.name; + } + #list(list3) { + if (List$isEmpty(list3)) { + return "[]"; + } + let char_out = 'charlist.from_string("'; + let list_out = "["; + let current = list3; + while (List$isNonEmpty(current)) { + let element = current.head; + current = current.tail; + if (list_out !== "[") { + list_out += ", "; + } + list_out += this.inspect(element); + if (char_out) { + if (Number.isInteger(element) && element >= 32 && element <= 126) { + char_out += String.fromCharCode(element); + } else { + char_out = null; + } + } + } + if (char_out) { + return char_out + '")'; + } else { + return list_out + "]"; + } + } + #string(str) { + let new_str = '"'; + for (let i = 0;i < str.length; i++) { + const char = str[i]; + switch (char) { + case ` +`: + new_str += "\\n"; + break; + case "\r": + new_str += "\\r"; + break; + case "\t": + new_str += "\\t"; + break; + case "\f": + new_str += "\\f"; + break; + case "\\": + new_str += "\\\\"; + break; + case '"': + new_str += "\\\""; + break; + default: + if (char < " " || char > "~" && char < " ") { + new_str += "\\u{" + char.charCodeAt(0).toString(16).toUpperCase().padStart(4, "0") + "}"; + } else { + new_str += char; + } + } + } + new_str += '"'; + return new_str; + } + #utfCodepoint(codepoint2) { + return `//utfcodepoint(${String.fromCodePoint(codepoint2.value)})`; + } + #bit_array(bits2) { + if (bits2.bitSize === 0) { + return "<<>>"; + } + let acc = "<<"; + for (let i = 0;i < bits2.byteSize - 1; i++) { + acc += bits2.byteAt(i).toString(); + acc += ", "; + } + if (bits2.byteSize * 8 === bits2.bitSize) { + acc += bits2.byteAt(bits2.byteSize - 1).toString(); + } else { + const trailingBitsCount = bits2.bitSize % 8; + acc += bits2.byteAt(bits2.byteSize - 1) >> 8 - trailingBitsCount; + acc += `:size(${trailingBitsCount})`; + } + acc += ">>"; + return acc; + } +} +function index2(data, key) { + if (data instanceof Dict) { + const result = get(data, key); + return Result$Ok(result.isOk() ? new Some(result[0]) : new None); + } + if (data instanceof WeakMap || data instanceof Map) { + const token = {}; + const entry = data.get(key, token); + if (entry === token) + return Result$Ok(new None); + return Result$Ok(new Some(entry)); + } + const key_is_int = Number.isInteger(key); + if (key_is_int && key >= 0 && key < 8 && isList(data)) { + let i = 0; + for (const value of data) { + if (i === key) + return Result$Ok(new Some(value)); + i++; + } + return Result$Error("Indexable"); + } + if (key_is_int && Array.isArray(data) || data && typeof data === "object" || data && Object.getPrototypeOf(data) === Object.prototype) { + if (key in data) + return Result$Ok(new Some(data[key])); + return Result$Ok(new None); + } + return Result$Error(key_is_int ? "Indexable" : "Dict"); +} +function list(data, decode, pushPath, index4, emptyList) { + if (!(isList(data) || Array.isArray(data))) { + const error = DecodeError$DecodeError("List", classify_dynamic(data), emptyList); + return [emptyList, arrayToList([error])]; + } + const decoded = []; + for (const element of data) { + const layer = decode(element); + const [out, errors] = layer; + if (List$isNonEmpty(errors)) { + const [_, errors2] = pushPath(layer, index4.toString()); + return [emptyList, errors2]; + } + decoded.push(out); + index4++; + } + return [arrayToList(decoded), emptyList]; +} +function float(data) { + if (typeof data === "number") + return Result$Ok(data); + return Result$Error(0); +} +function int(data) { + if (Number.isInteger(data)) + return Result$Ok(data); + return Result$Error(0); +} +function string2(data) { + if (typeof data === "string") + return Result$Ok(data); + return Result$Error(""); +} +function arrayToList(array) { + let list3 = List$Empty(); + let i = array.length; + while (i--) { + list3 = List$NonEmpty(array[i], list3); + } + return list3; +} +function isList(data) { + return List$isEmpty(data) || List$isNonEmpty(data); +} +function isResult(data) { + return Result$isOk(data) || Result$isError(data); +} + +// build/dev/javascript/gleam_stdlib/gleam/result.mjs +function map4(result, fun) { + if (result instanceof Ok) { + let x = result[0]; + return new Ok(fun(x)); + } else { + return result; + } +} +function map_error(result, fun) { + if (result instanceof Ok) { + return result; + } else { + let error = result[0]; + return new Error2(fun(error)); + } +} +function try$(result, fun) { + if (result instanceof Ok) { + let x = result[0]; + return fun(x); + } else { + return result; + } +} +function unwrap2(result, default$) { + if (result instanceof Ok) { + let v = result[0]; + return v; + } else { + return default$; + } +} +function replace_error(result, error) { + if (result instanceof Ok) { + return result; + } else { + return new Error2(error); + } +} +function values2(results) { + return filter_map(results, (result) => { + return result; + }); +} +// build/dev/javascript/gleam_erlang/gleam/erlang/process.mjs +class Normal extends CustomType { +} +var ExitReason$Normal$const = new Normal; +class Killed extends CustomType { +} +var ExitReason$Killed$const = new Killed; +class Anything extends CustomType { +} +var AnythingSelectorTag$Anything$const = new Anything; + +class Process extends CustomType { +} +var ProcessMonitorFlag$Process$const = new Process; +class TimerNotFound extends CustomType { +} +var Cancelled$TimerNotFound$const = new TimerNotFound; +class Kill extends CustomType { +} +var KillFlag$Kill$const = new Kill; +// build/dev/javascript/gleam_otp/gleam/otp/system.mjs +class Running extends CustomType { +} +var Mode$Running$const = new Running; +class Suspended extends CustomType { +} +var Mode$Suspended$const = new Suspended; +class NoDebug extends CustomType { +} +var DebugOption$NoDebug$const = new NoDebug; + +// build/dev/javascript/gleam_otp/gleam/otp/actor.mjs +class InitTimeout extends CustomType { +} +var StartError$InitTimeout$const = new InitTimeout; + +// build/dev/javascript/gleam_otp/gleam/otp/supervision.mjs +class Permanent extends CustomType { +} +var Restart$Permanent$const = new Permanent; +class Transient extends CustomType { +} +var Restart$Transient$const = new Transient; +class Temporary extends CustomType { +} +var Restart$Temporary$const = new Temporary; +class Supervisor extends CustomType { +} +var ChildType$Supervisor$const = new Supervisor; + +// build/dev/javascript/gleam_otp/gleam/otp/factory_supervisor.mjs +class SimpleOneForOne extends CustomType { +} +var Strategy$SimpleOneForOne$const = new SimpleOneForOne; + +// build/dev/javascript/gleam_stdlib/gleam/bool.mjs +function guard(requirement, consequence, alternative) { + if (requirement) { + return consequence; + } else { + return alternative(); + } +} + +// build/dev/javascript/gleam_stdlib/gleam/function.mjs +function identity2(x) { + return x; +} +// build/dev/javascript/gleam_json/gleam_json_ffi.mjs +function json_to_string(json) { + return JSON.stringify(json); +} +function object(entries) { + return Object.fromEntries(entries); +} +function identity3(x) { + return x; +} +function decode(string4) { + try { + const result = JSON.parse(string4); + return Result$Ok(result); + } catch (err) { + return Result$Error(getJsonDecodeError(err, string4)); + } +} +function getJsonDecodeError(stdErr, json) { + if (isUnexpectedEndOfInput(stdErr)) + return DecodeError$UnexpectedEndOfInput(); + return toUnexpectedByteError(stdErr, json); +} +function isUnexpectedEndOfInput(err) { + const unexpectedEndOfInputRegex = /((unexpected (end|eof))|(end of data)|(unterminated string)|(json( parse error|\.parse)\: expected '(\:|\}|\])'))/i; + return unexpectedEndOfInputRegex.test(err.message); +} +function toUnexpectedByteError(err, json) { + let converters = [ + v8UnexpectedByteError, + oldV8UnexpectedByteError, + jsCoreUnexpectedByteError, + spidermonkeyUnexpectedByteError + ]; + for (let converter of converters) { + let result = converter(err, json); + if (result) + return result; + } + return DecodeError$UnexpectedByte(""); +} +function v8UnexpectedByteError(err) { + const regex = /unexpected token '(.)', ".+" is not valid JSON/i; + const match = regex.exec(err.message); + if (!match) + return null; + const byte = toHex(match[1]); + return DecodeError$UnexpectedByte(byte); +} +function oldV8UnexpectedByteError(err) { + const regex = /unexpected token (.) in JSON at position (\d+)/i; + const match = regex.exec(err.message); + if (!match) + return null; + const byte = toHex(match[1]); + return DecodeError$UnexpectedByte(byte); +} +function spidermonkeyUnexpectedByteError(err, json) { + const regex = /(unexpected character|expected .*) at line (\d+) column (\d+)/i; + const match = regex.exec(err.message); + if (!match) + return null; + const line = Number(match[2]); + const column = Number(match[3]); + const position = getPositionFromMultiline(line, column, json); + const byte = toHex(json[position]); + return DecodeError$UnexpectedByte(byte); +} +function jsCoreUnexpectedByteError(err) { + const regex = /unexpected (identifier|token) "(.)"/i; + const match = regex.exec(err.message); + if (!match) + return null; + const byte = toHex(match[2]); + return DecodeError$UnexpectedByte(byte); +} +function toHex(char) { + return "0x" + char.charCodeAt(0).toString(16).toUpperCase(); +} +function getPositionFromMultiline(line, column, string4) { + if (line === 1) + return column - 1; + let currentLn = 1; + let position = 0; + string4.split("").find((char, idx) => { + if (char === ` +`) + currentLn += 1; + if (currentLn === line) { + position = idx + column; + return true; + } + return false; + }); + return position; +} + +// build/dev/javascript/gleam_json/gleam/json.mjs +class UnexpectedEndOfInput extends CustomType { +} +var DecodeError$UnexpectedEndOfInput$const = new UnexpectedEndOfInput; +var DecodeError$UnexpectedEndOfInput = () => DecodeError$UnexpectedEndOfInput$const; +class UnexpectedByte extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } +} +var DecodeError$UnexpectedByte = ($0) => new UnexpectedByte($0); +class UnableToDecode extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } +} +function do_parse(json, decoder) { + return try$(decode(json), (dynamic_value) => { + let _pipe = run(dynamic_value, decoder); + return map_error(_pipe, (var0) => { + return new UnableToDecode(var0); + }); + }); +} +function parse(json, decoder) { + return do_parse(json, decoder); +} +function to_string2(json) { + return json_to_string(json); +} +function string4(input) { + return identity3(input); +} +function object2(entries) { + return object(entries); +} +// build/dev/javascript/houdini/houdini.ffi.mjs +function escape(string5) { + return string5.replaceAll(/[><&"']/g, (replaced) => { + switch (replaced) { + case ">": + return ">"; + case "<": + return "<"; + case "'": + return "'"; + case "&": + return "&"; + case '"': + return """; + default: + return replaced; + } + }); +} + +// build/dev/javascript/lustre/lustre/internals/constants.mjs +var empty_list = List$Empty$const; +var error_nil = /* @__PURE__ */ new Error2(undefined); +function singleton_list(item) { + return prepend(item, empty_list); +} + +// build/dev/javascript/lustre/lustre/vdom/vattr.ffi.mjs +var GT = /* @__PURE__ */ Order$Gt(); +var LT = /* @__PURE__ */ Order$Lt(); +var EQ = /* @__PURE__ */ Order$Eq(); +function compare2(a, b) { + if (a.name === b.name) { + return EQ; + } else if (a.name < b.name) { + return LT; + } else { + return GT; + } +} + +// build/dev/javascript/lustre/lustre/vdom/vattr.mjs +class Attribute extends CustomType { + constructor(kind, name, value) { + super(); + this.kind = kind; + this.name = name; + this.value = value; + } +} +class Property extends CustomType { + constructor(kind, name, value) { + super(); + this.kind = kind; + this.name = name; + this.value = value; + } +} +class Event2 extends CustomType { + constructor(kind, name, handler, include, prevent_default, stop_propagation, debounce, throttle) { + super(); + this.kind = kind; + this.name = name; + this.handler = handler; + this.include = include; + this.prevent_default = prevent_default; + this.stop_propagation = stop_propagation; + this.debounce = debounce; + this.throttle = throttle; + } +} +class Handler extends CustomType { + constructor(prevent_default, stop_propagation, message) { + super(); + this.prevent_default = prevent_default; + this.stop_propagation = stop_propagation; + this.message = message; + } +} +class Never extends CustomType { + constructor(kind) { + super(); + this.kind = kind; + } +} +class Always extends CustomType { + constructor(kind) { + super(); + this.kind = kind; + } +} +var attribute_kind = 0; +var property_kind = 1; +var event_kind = 2; +var never_kind = 0; +var never = /* @__PURE__ */ new Never(never_kind); +var always_kind = 2; +var always = /* @__PURE__ */ new Always(always_kind); +function attribute(name, value) { + return new Attribute(attribute_kind, name, value); +} +function event(name, handler, include, prevent_default, stop_propagation, debounce, throttle) { + return new Event2(event_kind, name, handler, include, prevent_default, stop_propagation, debounce, throttle); +} +function merge(loop$attributes, loop$merged) { + while (true) { + let attributes = loop$attributes; + let merged = loop$merged; + if (attributes instanceof Empty) { + return merged; + } else { + let $ = attributes.head; + if ($ instanceof Attribute) { + let $1 = $.name; + if ($1 === "") { + let rest = attributes.tail; + loop$attributes = rest; + loop$merged = merged; + } else if ($1 === "class") { + let $2 = $.value; + if ($2 === "") { + let rest = attributes.tail; + loop$attributes = rest; + loop$merged = merged; + } else { + let $3 = attributes.tail; + if ($3 instanceof Empty) { + let attribute$1 = $; + let rest = $3; + loop$attributes = rest; + loop$merged = prepend(attribute$1, merged); + } else { + let $4 = $3.head; + if ($4 instanceof Attribute) { + let $5 = $4.name; + if ($5 === "class") { + let kind = $.kind; + let class1 = $2; + let rest = $3.tail; + let class2 = $4.value; + let value = class1 + " " + class2; + let attribute$1 = new Attribute(kind, "class", value); + loop$attributes = prepend(attribute$1, rest); + loop$merged = merged; + } else { + let attribute$1 = $; + let rest = $3; + loop$attributes = rest; + loop$merged = prepend(attribute$1, merged); + } + } else { + let attribute$1 = $; + let rest = $3; + loop$attributes = rest; + loop$merged = prepend(attribute$1, merged); + } + } + } + } else if ($1 === "style") { + let $2 = $.value; + if ($2 === "") { + let rest = attributes.tail; + loop$attributes = rest; + loop$merged = merged; + } else { + let $3 = attributes.tail; + if ($3 instanceof Empty) { + let attribute$1 = $; + let rest = $3; + loop$attributes = rest; + loop$merged = prepend(attribute$1, merged); + } else { + let $4 = $3.head; + if ($4 instanceof Attribute) { + let $5 = $4.name; + if ($5 === "style") { + let kind = $.kind; + let style1 = $2; + let rest = $3.tail; + let style2 = $4.value; + let value = style1 + ";" + style2; + let attribute$1 = new Attribute(kind, "style", value); + loop$attributes = prepend(attribute$1, rest); + loop$merged = merged; + } else { + let attribute$1 = $; + let rest = $3; + loop$attributes = rest; + loop$merged = prepend(attribute$1, merged); + } + } else { + let attribute$1 = $; + let rest = $3; + loop$attributes = rest; + loop$merged = prepend(attribute$1, merged); + } + } + } + } else { + let attribute$1 = $; + let rest = attributes.tail; + loop$attributes = rest; + loop$merged = prepend(attribute$1, merged); + } + } else { + let attribute$1 = $; + let rest = attributes.tail; + loop$attributes = rest; + loop$merged = prepend(attribute$1, merged); + } + } + } +} +function prepare(attributes) { + if (attributes instanceof Empty) { + return attributes; + } else { + let $ = attributes.tail; + if ($ instanceof Empty) { + return attributes; + } else { + let _pipe = attributes; + let _pipe$1 = sort(_pipe, (a, b) => { + return compare2(b, a); + }); + return merge(_pipe$1, empty_list); + } + } +} + +// build/dev/javascript/lustre/lustre/attribute.mjs +function attribute2(name, value) { + return attribute(name, value); +} +function class$(name) { + return attribute2("class", name); +} +function href(url) { + return attribute2("href", url); +} +function name(element_name) { + return attribute2("name", element_name); +} +function placeholder(text) { + return attribute2("placeholder", text); +} +function type_(control_type) { + return attribute2("type", control_type); +} +function value(control_value) { + return attribute2("value", control_value); +} + +// build/dev/javascript/lustre/lustre/effect.mjs +class Effect extends CustomType { + constructor(synchronous, before_paint, after_paint) { + super(); + this.synchronous = synchronous; + this.before_paint = before_paint; + this.after_paint = after_paint; + } +} + +class Actions extends CustomType { + constructor(dispatch, emit, select, root, provide, subscribe, unsubscribe) { + super(); + this.dispatch = dispatch; + this.emit = emit; + this.select = select; + this.root = root; + this.provide = provide; + this.subscribe = subscribe; + this.unsubscribe = unsubscribe; + } +} +var empty = /* @__PURE__ */ new Effect(empty_list, empty_list, empty_list); +function none() { + return empty; +} +function from2(effect) { + let task = (actions) => { + let dispatch = actions.dispatch; + return effect(dispatch); + }; + return new Effect(singleton_list(task), empty.before_paint, empty.after_paint); +} +function batch(effects) { + return fold2(effects, empty, (acc, eff) => { + return new Effect(fold2(eff.synchronous, acc.synchronous, prepend2), fold2(eff.before_paint, acc.before_paint, prepend2), fold2(eff.after_paint, acc.after_paint, prepend2)); + }); +} +function perform(effect, dispatch, emit, select, root, provide, subscribe, unsubscribe) { + let actions = new Actions(dispatch, emit, select, root, provide, subscribe, unsubscribe); + return each(effect.synchronous, (run2) => { + return run2(actions); + }); +} + +// build/dev/javascript/lustre/lustre/internals/mutable_map.ffi.mjs +function empty2() { + return null; +} +function get2(map5, key) { + return map5?.get(key); +} +function get_or_compute(map5, key, compute) { + return map5?.get(key) ?? compute(); +} +function has_key(map5, key) { + return map5 && map5.has(key); +} +function insert2(map5, key, value2) { + map5 ??= new Map; + map5.set(key, value2); + return map5; +} +function remove(map5, key) { + map5?.delete(key); + return map5; +} + +// build/dev/javascript/lustre/lustre/internals/ref.ffi.mjs +function sameValueZero(x, y) { + if (typeof x === "number" && typeof y === "number") { + return x === y || x !== x && y !== y; + } + return x === y; +} + +// build/dev/javascript/lustre/lustre/internals/ref.mjs +function equal_lists(loop$xs, loop$ys) { + while (true) { + let xs = loop$xs; + let ys = loop$ys; + if (xs instanceof Empty) { + if (ys instanceof Empty) { + return true; + } else { + return false; + } + } else if (ys instanceof Empty) { + return false; + } else { + let x = xs.head; + let xs$1 = xs.tail; + let y = ys.head; + let ys$1 = ys.tail; + let $ = sameValueZero(x, y); + if ($) { + loop$xs = xs$1; + loop$ys = ys$1; + } else { + return $; + } + } + } +} + +// build/dev/javascript/lustre/lustre/vdom/vnode.mjs +class Fragment extends CustomType { + constructor(kind, key, children, keyed_children) { + super(); + this.kind = kind; + this.key = key; + this.children = children; + this.keyed_children = keyed_children; + } +} +class Element2 extends CustomType { + constructor(kind, key, namespace, tag, attributes, children, keyed_children, self_closing, void$) { + super(); + this.kind = kind; + this.key = key; + this.namespace = namespace; + this.tag = tag; + this.attributes = attributes; + this.children = children; + this.keyed_children = keyed_children; + this.self_closing = self_closing; + this.void = void$; + } +} +class Text extends CustomType { + constructor(kind, key, content) { + super(); + this.kind = kind; + this.key = key; + this.content = content; + } +} +class UnsafeInnerHtml extends CustomType { + constructor(kind, key, namespace, tag, attributes, inner_html) { + super(); + this.kind = kind; + this.key = key; + this.namespace = namespace; + this.tag = tag; + this.attributes = attributes; + this.inner_html = inner_html; + } +} +class Map2 extends CustomType { + constructor(kind, key, mapper, child) { + super(); + this.kind = kind; + this.key = key; + this.mapper = mapper; + this.child = child; + } +} +class Memo extends CustomType { + constructor(kind, key, dependencies, view) { + super(); + this.kind = kind; + this.key = key; + this.dependencies = dependencies; + this.view = view; + } +} +var fragment_kind = 0; +var element_kind = 1; +var text_kind = 2; +var unsafe_inner_html_kind = 3; +var map_kind = 4; +var memo_kind = 5; +function fragment(key, children, keyed_children) { + return new Fragment(fragment_kind, key, children, keyed_children); +} +function element(key, namespace, tag, attributes, children, keyed_children, self_closing, void$) { + return new Element2(element_kind, key, namespace, tag, prepare(attributes), children, keyed_children, self_closing, void$); +} +function is_void_html_element(tag, namespace) { + if (namespace === "") { + if (tag === "area") { + return true; + } else if (tag === "base") { + return true; + } else if (tag === "br") { + return true; + } else if (tag === "col") { + return true; + } else if (tag === "embed") { + return true; + } else if (tag === "hr") { + return true; + } else if (tag === "img") { + return true; + } else if (tag === "input") { + return true; + } else if (tag === "link") { + return true; + } else if (tag === "meta") { + return true; + } else if (tag === "param") { + return true; + } else if (tag === "source") { + return true; + } else if (tag === "track") { + return true; + } else if (tag === "wbr") { + return true; + } else { + return false; + } + } else { + return false; + } +} +function text(key, content) { + return new Text(text_kind, key, content); +} +function unsafe_inner_html(key, namespace, tag, attributes, inner_html) { + return new UnsafeInnerHtml(unsafe_inner_html_kind, key, namespace, tag, prepare(attributes), inner_html); +} +function map5(element2, mapper) { + if (element2 instanceof Map2) { + let child_mapper = element2.mapper; + return new Map2(map_kind, element2.key, (handler) => { + return identity2(mapper)(child_mapper(handler)); + }, identity2(element2.child)); + } else { + return new Map2(map_kind, element2.key, identity2(mapper), identity2(element2)); + } +} +function memo(key, dependencies, view) { + return new Memo(memo_kind, key, dependencies, view); +} +function to_keyed(key, node) { + if (node instanceof Fragment) { + return new Fragment(node.kind, key, node.children, node.keyed_children); + } else if (node instanceof Element2) { + return new Element2(node.kind, key, node.namespace, node.tag, node.attributes, node.children, node.keyed_children, node.self_closing, node.void); + } else if (node instanceof Text) { + return new Text(node.kind, key, node.content); + } else if (node instanceof UnsafeInnerHtml) { + return new UnsafeInnerHtml(node.kind, key, node.namespace, node.tag, node.attributes, node.inner_html); + } else if (node instanceof Map2) { + let child = node.child; + return new Map2(node.kind, key, node.mapper, to_keyed(key, child)); + } else { + let view = node.view; + return new Memo(node.kind, key, node.dependencies, () => { + return to_keyed(key, view()); + }); + } +} + +// build/dev/javascript/lustre/lustre/element.mjs +class Html extends CustomType { +} +var DocumentType$Html$const = new Html; + +class HeadOnly extends CustomType { +} +var DocumentType$HeadOnly$const = new HeadOnly; + +class BodyOnly extends CustomType { +} +var DocumentType$BodyOnly$const = new BodyOnly; + +class HeadAndBody extends CustomType { +} +var DocumentType$HeadAndBody$const = new HeadAndBody; + +class Other extends CustomType { +} +var DocumentType$Other$const = new Other; +function element2(tag, attributes, children) { + return element("", "", tag, attributes, children, empty2(), false, is_void_html_element(tag, "")); +} +function text2(content) { + return text("", content); +} +function none2() { + return text("", ""); +} +function unsafe_raw_html(namespace, tag, attributes, inner_html) { + return unsafe_inner_html("", namespace, tag, attributes, inner_html); +} +function memo2(dependencies, view) { + return memo("", dependencies, view); +} +function ref(value2) { + return identity2(value2); +} +function map6(element3, f) { + return map5(element3, f); +} + +// build/dev/javascript/lustre/lustre/element/html.mjs +function text3(content) { + return text2(content); +} +function style(attrs, css) { + return unsafe_raw_html("", "style", attrs, css); +} +function article(attrs, children) { + return element2("article", attrs, children); +} +function header(attrs, children) { + return element2("header", attrs, children); +} +function h1(attrs, children) { + return element2("h1", attrs, children); +} +function h2(attrs, children) { + return element2("h2", attrs, children); +} +function main(attrs, children) { + return element2("main", attrs, children); +} +function section(attrs, children) { + return element2("section", attrs, children); +} +function div(attrs, children) { + return element2("div", attrs, children); +} +function p(attrs, children) { + return element2("p", attrs, children); +} +function a(attrs, children) { + return element2("a", attrs, children); +} +function span(attrs, children) { + return element2("span", attrs, children); +} +function strong(attrs, children) { + return element2("strong", attrs, children); +} +function button(attrs, children) { + return element2("button", attrs, children); +} +function form(attrs, children) { + return element2("form", attrs, children); +} +function input(attrs) { + return element2("input", attrs, empty_list); +} + +// build/dev/javascript/lustre/lustre/vdom/patch.mjs +class Patch extends CustomType { + constructor(index4, path, removed, changes, children) { + super(); + this.index = index4; + this.path = path; + this.removed = removed; + this.changes = changes; + this.children = children; + } +} +class ReplaceText extends CustomType { + constructor(kind, content) { + super(); + this.kind = kind; + this.content = content; + } +} +class ReplaceInnerHtml extends CustomType { + constructor(kind, inner_html) { + super(); + this.kind = kind; + this.inner_html = inner_html; + } +} +class Update extends CustomType { + constructor(kind, added, removed) { + super(); + this.kind = kind; + this.added = added; + this.removed = removed; + } +} +class Move extends CustomType { + constructor(kind, key, before) { + super(); + this.kind = kind; + this.key = key; + this.before = before; + } +} +class Replace extends CustomType { + constructor(kind, index4, with$) { + super(); + this.kind = kind; + this.index = index4; + this.with = with$; + } +} +class Remove extends CustomType { + constructor(kind, index4) { + super(); + this.kind = kind; + this.index = index4; + } +} +class Insert extends CustomType { + constructor(kind, children, before) { + super(); + this.kind = kind; + this.children = children; + this.before = before; + } +} +var replace_text_kind = 0; +var replace_inner_html_kind = 1; +var update_kind = 2; +var move_kind = 3; +var remove_kind = 4; +var replace_kind = 5; +var insert_kind = 6; +function new$3(index4, removed, changes, children) { + return new Patch(index4, empty_list, removed, changes, children); +} +function replace_text(content) { + return new ReplaceText(replace_text_kind, content); +} +function replace_inner_html(inner_html) { + return new ReplaceInnerHtml(replace_inner_html_kind, inner_html); +} +function update(added, removed) { + return new Update(update_kind, added, removed); +} +function move(key, before) { + return new Move(move_kind, key, before); +} +function remove2(index4) { + return new Remove(remove_kind, index4); +} +function replace2(index4, with$) { + return new Replace(replace_kind, index4, with$); +} +function insert3(children, before) { + return new Insert(insert_kind, children, before); +} +function add_parent(child, index4) { + return new Patch(index4, prepend(child.index, child.path), child.removed, child.changes, child.children); +} + +// build/dev/javascript/lustre/lustre/runtime/transport.mjs +class Mount extends CustomType { + constructor(kind, open_shadow_root, will_adopt_styles, observed_attributes, observed_properties, requested_contexts, provided_contexts, vdom, memos) { + super(); + this.kind = kind; + this.open_shadow_root = open_shadow_root; + this.will_adopt_styles = will_adopt_styles; + this.observed_attributes = observed_attributes; + this.observed_properties = observed_properties; + this.requested_contexts = requested_contexts; + this.provided_contexts = provided_contexts; + this.vdom = vdom; + this.memos = memos; + } +} +class Reconcile extends CustomType { + constructor(kind, patch, memos) { + super(); + this.kind = kind; + this.patch = patch; + this.memos = memos; + } +} +class Emit extends CustomType { + constructor(kind, name2, data) { + super(); + this.kind = kind; + this.name = name2; + this.data = data; + } +} +class Provide extends CustomType { + constructor(kind, key, value2) { + super(); + this.kind = kind; + this.key = key; + this.value = value2; + } +} +class Subscribe extends CustomType { + constructor(kind, key) { + super(); + this.kind = kind; + this.key = key; + } +} +class Unsubscribe extends CustomType { + constructor(kind, key) { + super(); + this.kind = kind; + this.key = key; + } +} +class Batch extends CustomType { + constructor(kind, messages) { + super(); + this.kind = kind; + this.messages = messages; + } +} +var ServerMessage$isBatch = (value2) => value2 instanceof Batch; +class AttributeChanged extends CustomType { + constructor(kind, name2, value2) { + super(); + this.kind = kind; + this.name = name2; + this.value = value2; + } +} +var ServerMessage$isAttributeChanged = (value2) => value2 instanceof AttributeChanged; +class PropertyChanged extends CustomType { + constructor(kind, name2, value2) { + super(); + this.kind = kind; + this.name = name2; + this.value = value2; + } +} +var ServerMessage$isPropertyChanged = (value2) => value2 instanceof PropertyChanged; +class EventFired extends CustomType { + constructor(kind, path, name2, event2) { + super(); + this.kind = kind; + this.path = path; + this.name = name2; + this.event = event2; + } +} +var ServerMessage$isEventFired = (value2) => value2 instanceof EventFired; +class ContextProvided extends CustomType { + constructor(kind, key, value2) { + super(); + this.kind = kind; + this.key = key; + this.value = value2; + } +} +var ServerMessage$isContextProvided = (value2) => value2 instanceof ContextProvided; +var mount_kind = 0; +var reconcile_kind = 1; +var emit_kind = 2; +var provide_kind = 3; +var subscribe_kind = 4; +var unsubscribe_kind = 5; +function mount(open_shadow_root, will_adopt_styles, observed_attributes, observed_properties, requested_contexts, provided_contexts, vdom, memos) { + return new Mount(mount_kind, open_shadow_root, will_adopt_styles, observed_attributes, observed_properties, requested_contexts, provided_contexts, vdom, memos); +} +function reconcile(patch, memos) { + return new Reconcile(reconcile_kind, patch, memos); +} +function emit(name2, data) { + return new Emit(emit_kind, name2, data); +} +function provide(key, value2) { + return new Provide(provide_kind, key, value2); +} +function subscribe(key) { + return new Subscribe(subscribe_kind, key); +} +function unsubscribe(key) { + return new Unsubscribe(unsubscribe_kind, key); +} + +// build/dev/javascript/lustre/lustre/vdom/path.mjs +class Root extends CustomType { +} +var Path$Root$const = new Root; + +class Key extends CustomType { + constructor(key, parent) { + super(); + this.key = key; + this.parent = parent; + } +} + +class Index extends CustomType { + constructor(index4, parent) { + super(); + this.index = index4; + this.parent = parent; + } +} + +class Subtree extends CustomType { + constructor(parent) { + super(); + this.parent = parent; + } +} +var separator_subtree = "\r"; +var separator_element = "\t"; +var separator_event = ` +`; +var root = Path$Root$const; +function finish_to_string(acc) { + if (acc instanceof Empty) { + return ""; + } else { + let segments = acc.tail; + return concat2(segments); + } +} +function do_to_string(loop$full, loop$path, loop$acc) { + while (true) { + let full = loop$full; + let path = loop$path; + let acc = loop$acc; + if (path instanceof Root) { + return finish_to_string(acc); + } else if (path instanceof Key) { + let key = path.key; + let parent = path.parent; + loop$full = full; + loop$path = parent; + loop$acc = prepend(separator_element, prepend(key, acc)); + } else if (path instanceof Index) { + let index4 = path.index; + let parent = path.parent; + let acc$1 = prepend(separator_element, prepend(to_string(index4), acc)); + loop$full = full; + loop$path = parent; + loop$acc = acc$1; + } else if (!full) { + return finish_to_string(acc); + } else { + let parent = path.parent; + if (acc instanceof Empty) { + loop$full = full; + loop$path = parent; + loop$acc = acc; + } else { + let acc$1 = acc.tail; + loop$full = full; + loop$path = parent; + loop$acc = prepend(separator_subtree, acc$1); + } + } + } +} +function to_string4(path) { + return do_to_string(true, path, empty_list); +} +function do_matches(loop$path, loop$candidates) { + while (true) { + let path = loop$path; + let candidates = loop$candidates; + if (candidates instanceof Empty) { + return false; + } else { + let candidate = candidates.head; + let rest = candidates.tail; + let $ = starts_with(path, candidate); + if ($) { + return $; + } else { + loop$path = path; + loop$candidates = rest; + } + } + } +} +function matches(path, candidates) { + if (candidates instanceof Empty) { + return false; + } else { + return do_matches(to_string4(path), candidates); + } +} +function split_subtree_path(path) { + return split2(path, separator_subtree); +} +function add2(parent, index4, key) { + if (key === "") { + return new Index(index4, parent); + } else { + return new Key(key, parent); + } +} +function subtree(path) { + return new Subtree(path); +} +function event2(path, event3) { + return do_to_string(false, path, prepend(separator_event, prepend(event3, empty_list))); +} +function child(path) { + return do_to_string(false, path, empty_list); +} + +// build/dev/javascript/lustre/lustre/vdom/cache.mjs +class Cache extends CustomType { + constructor(events, vdoms, old_vdoms, dispatched_paths, next_dispatched_paths) { + super(); + this.events = events; + this.vdoms = vdoms; + this.old_vdoms = old_vdoms; + this.dispatched_paths = dispatched_paths; + this.next_dispatched_paths = next_dispatched_paths; + } +} + +class Events extends CustomType { + constructor(handlers, children) { + super(); + this.handlers = handlers; + this.children = children; + } +} + +class Child extends CustomType { + constructor(mapper, events) { + super(); + this.mapper = mapper; + this.events = events; + } +} + +class AddedChildren extends CustomType { + constructor(handlers, children, vdoms) { + super(); + this.handlers = handlers; + this.children = children; + this.vdoms = vdoms; + } +} + +class DecodedEvent extends CustomType { + constructor(path, handler) { + super(); + this.path = path; + this.handler = handler; + } +} + +class DispatchedEvent extends CustomType { + constructor(path) { + super(); + this.path = path; + } +} +function compose_mapper(mapper, child_mapper) { + return (message) => { + return mapper(child_mapper(message)); + }; +} +function new_events() { + return new Events(empty2(), empty2()); +} +function new$4() { + return new Cache(new_events(), empty2(), empty2(), empty_list, empty_list); +} +function do_add_event(handlers, path, name2, handler) { + return insert2(handlers, event2(path, name2), handler); +} +function add_attributes(handlers, path, attributes) { + return fold2(attributes, handlers, (events, attribute3) => { + if (attribute3 instanceof Event2) { + let name2 = attribute3.name; + let handler = attribute3.handler; + return do_add_event(events, path, name2, handler); + } else { + return events; + } + }); +} +function do_add_children(loop$handlers, loop$children, loop$vdoms, loop$parent, loop$child_index, loop$nodes) { + while (true) { + let handlers = loop$handlers; + let children = loop$children; + let vdoms = loop$vdoms; + let parent = loop$parent; + let child_index = loop$child_index; + let nodes = loop$nodes; + let next = child_index + 1; + if (nodes instanceof Empty) { + return new AddedChildren(handlers, children, vdoms); + } else { + let $ = nodes.head; + if ($ instanceof Fragment) { + let rest = nodes.tail; + let key = $.key; + let nodes$1 = $.children; + let path = add2(parent, child_index, key); + let $1 = do_add_children(handlers, children, vdoms, path, 0, nodes$1); + let handlers$1 = $1.handlers; + let children$1 = $1.children; + let vdoms$1 = $1.vdoms; + loop$handlers = handlers$1; + loop$children = children$1; + loop$vdoms = vdoms$1; + loop$parent = parent; + loop$child_index = next; + loop$nodes = rest; + } else if ($ instanceof Element2) { + let rest = nodes.tail; + let key = $.key; + let attributes = $.attributes; + let nodes$1 = $.children; + let path = add2(parent, child_index, key); + let handlers$1 = add_attributes(handlers, path, attributes); + let $1 = do_add_children(handlers$1, children, vdoms, path, 0, nodes$1); + let handlers$2 = $1.handlers; + let children$1 = $1.children; + let vdoms$1 = $1.vdoms; + loop$handlers = handlers$2; + loop$children = children$1; + loop$vdoms = vdoms$1; + loop$parent = parent; + loop$child_index = next; + loop$nodes = rest; + } else if ($ instanceof Text) { + let rest = nodes.tail; + loop$handlers = handlers; + loop$children = children; + loop$vdoms = vdoms; + loop$parent = parent; + loop$child_index = next; + loop$nodes = rest; + } else if ($ instanceof UnsafeInnerHtml) { + let rest = nodes.tail; + let key = $.key; + let attributes = $.attributes; + let path = add2(parent, child_index, key); + let handlers$1 = add_attributes(handlers, path, attributes); + loop$handlers = handlers$1; + loop$children = children; + loop$vdoms = vdoms; + loop$parent = parent; + loop$child_index = next; + loop$nodes = rest; + } else if ($ instanceof Map2) { + let rest = nodes.tail; + let key = $.key; + let mapper = $.mapper; + let child2 = $.child; + let path = add2(parent, child_index, key); + let added = do_add_children(empty2(), empty2(), vdoms, subtree(path), 0, singleton_list(child2)); + let vdoms$1 = added.vdoms; + let child_events = new Events(added.handlers, added.children); + let child$1 = new Child(mapper, child_events); + let children$1 = insert2(children, child(path), child$1); + loop$handlers = handlers; + loop$children = children$1; + loop$vdoms = vdoms$1; + loop$parent = parent; + loop$child_index = next; + loop$nodes = rest; + } else { + let rest = nodes.tail; + let view = $.view; + let child_node = view(); + let vdoms$1 = insert2(vdoms, view, child_node); + let next$1 = child_index; + let rest$1 = prepend(child_node, rest); + loop$handlers = handlers; + loop$children = children; + loop$vdoms = vdoms$1; + loop$parent = parent; + loop$child_index = next$1; + loop$nodes = rest$1; + } + } + } +} +function add_children(cache, events, path, child_index, nodes) { + let vdoms = cache.vdoms; + let handlers = events.handlers; + let children = events.children; + let $ = do_add_children(handlers, children, vdoms, path, child_index, nodes); + let handlers$1 = $.handlers; + let children$1 = $.children; + let vdoms$1 = $.vdoms; + return [ + new Cache(cache.events, vdoms$1, cache.old_vdoms, cache.dispatched_paths, cache.next_dispatched_paths), + new Events(handlers$1, children$1) + ]; +} +function add_child(cache, events, parent, index4, child2) { + let children = singleton_list(child2); + return add_children(cache, events, parent, index4, children); +} +function from_node(root2) { + let cache = new$4(); + let $ = add_child(cache, cache.events, root, 0, root2); + let cache$1 = $[0]; + let events$1 = $[1]; + return new Cache(events$1, cache$1.vdoms, cache$1.old_vdoms, cache$1.dispatched_paths, cache$1.next_dispatched_paths); +} +function tick(cache) { + return new Cache(cache.events, empty2(), cache.vdoms, cache.next_dispatched_paths, empty_list); +} +function events(cache) { + return cache.events; +} +function update_events(cache, events2) { + return new Cache(events2, cache.vdoms, cache.old_vdoms, cache.dispatched_paths, cache.next_dispatched_paths); +} +function memos(cache) { + return cache.vdoms; +} +function get_old_memo(cache, old, new$5) { + return get_or_compute(cache.old_vdoms, old, new$5); +} +function keep_memo(cache, old, new$5) { + let node = get_or_compute(cache.old_vdoms, old, new$5); + let vdoms = insert2(cache.vdoms, new$5, node); + return new Cache(cache.events, vdoms, cache.old_vdoms, cache.dispatched_paths, cache.next_dispatched_paths); +} +function add_memo(cache, new$5, node) { + let vdoms = insert2(cache.vdoms, new$5, node); + return new Cache(cache.events, vdoms, cache.old_vdoms, cache.dispatched_paths, cache.next_dispatched_paths); +} +function get_subtree(events2, path, old_mapper) { + let child2 = get_or_compute(events2.children, path, () => { + return new Child(old_mapper, new_events()); + }); + return child2.events; +} +function update_subtree(parent, path, mapper, events2) { + let new_child = new Child(mapper, events2); + let children = insert2(parent.children, path, new_child); + return new Events(parent.handlers, children); +} +function add_event(events2, path, name2, handler) { + let handlers = do_add_event(events2.handlers, path, name2, handler); + return new Events(handlers, events2.children); +} +function do_remove_event(handlers, path, name2) { + return remove(handlers, event2(path, name2)); +} +function remove_event(events2, path, name2) { + let handlers = do_remove_event(events2.handlers, path, name2); + return new Events(handlers, events2.children); +} +function remove_attributes(handlers, path, attributes) { + return fold2(attributes, handlers, (events2, attribute3) => { + if (attribute3 instanceof Event2) { + let name2 = attribute3.name; + return do_remove_event(events2, path, name2); + } else { + return events2; + } + }); +} +function do_remove_children(loop$handlers, loop$children, loop$vdoms, loop$parent, loop$index, loop$nodes) { + while (true) { + let handlers = loop$handlers; + let children = loop$children; + let vdoms = loop$vdoms; + let parent = loop$parent; + let index4 = loop$index; + let nodes = loop$nodes; + let next = index4 + 1; + if (nodes instanceof Empty) { + return new Events(handlers, children); + } else { + let $ = nodes.head; + if ($ instanceof Fragment) { + let rest = nodes.tail; + let key = $.key; + let nodes$1 = $.children; + let path = add2(parent, index4, key); + let $1 = do_remove_children(handlers, children, vdoms, path, 0, nodes$1); + let handlers$1 = $1.handlers; + let children$1 = $1.children; + loop$handlers = handlers$1; + loop$children = children$1; + loop$vdoms = vdoms; + loop$parent = parent; + loop$index = next; + loop$nodes = rest; + } else if ($ instanceof Element2) { + let rest = nodes.tail; + let key = $.key; + let attributes = $.attributes; + let nodes$1 = $.children; + let path = add2(parent, index4, key); + let handlers$1 = remove_attributes(handlers, path, attributes); + let $1 = do_remove_children(handlers$1, children, vdoms, path, 0, nodes$1); + let handlers$2 = $1.handlers; + let children$1 = $1.children; + loop$handlers = handlers$2; + loop$children = children$1; + loop$vdoms = vdoms; + loop$parent = parent; + loop$index = next; + loop$nodes = rest; + } else if ($ instanceof Text) { + let rest = nodes.tail; + loop$handlers = handlers; + loop$children = children; + loop$vdoms = vdoms; + loop$parent = parent; + loop$index = next; + loop$nodes = rest; + } else if ($ instanceof UnsafeInnerHtml) { + let rest = nodes.tail; + let key = $.key; + let attributes = $.attributes; + let path = add2(parent, index4, key); + let handlers$1 = remove_attributes(handlers, path, attributes); + loop$handlers = handlers$1; + loop$children = children; + loop$vdoms = vdoms; + loop$parent = parent; + loop$index = next; + loop$nodes = rest; + } else if ($ instanceof Map2) { + let rest = nodes.tail; + let key = $.key; + let path = add2(parent, index4, key); + let children$1 = remove(children, child(path)); + loop$handlers = handlers; + loop$children = children$1; + loop$vdoms = vdoms; + loop$parent = parent; + loop$index = next; + loop$nodes = rest; + } else { + let rest = nodes.tail; + let view = $.view; + let $1 = has_key(vdoms, view); + if ($1) { + let child2 = get2(vdoms, view); + let nodes$1 = prepend(child2, rest); + loop$handlers = handlers; + loop$children = children; + loop$vdoms = vdoms; + loop$parent = parent; + loop$index = index4; + loop$nodes = nodes$1; + } else { + loop$handlers = handlers; + loop$children = children; + loop$vdoms = vdoms; + loop$parent = parent; + loop$index = next; + loop$nodes = rest; + } + } + } + } +} +function remove_child(cache, events2, parent, child_index, child2) { + return do_remove_children(events2.handlers, events2.children, cache.old_vdoms, parent, child_index, singleton_list(child2)); +} +function replace_child(cache, events2, parent, child_index, prev, next) { + let events$1 = remove_child(cache, events2, parent, child_index, prev); + return add_child(cache, events$1, parent, child_index, next); +} +function get_handler(loop$events, loop$path, loop$mapper) { + while (true) { + let events2 = loop$events; + let path = loop$path; + let mapper = loop$mapper; + if (path instanceof Empty) { + return error_nil; + } else { + let $ = path.tail; + if ($ instanceof Empty) { + let key = path.head; + let $1 = has_key(events2.handlers, key); + if ($1) { + let handler = get2(events2.handlers, key); + return new Ok(map3(handler, (handler2) => { + return new Handler(handler2.prevent_default, handler2.stop_propagation, identity2(mapper)(handler2.message)); + })); + } else { + return error_nil; + } + } else { + let key = path.head; + let path$1 = $; + let $1 = has_key(events2.children, key); + if ($1) { + let child2 = get2(events2.children, key); + let mapper$1 = compose_mapper(mapper, child2.mapper); + loop$events = child2.events; + loop$path = path$1; + loop$mapper = mapper$1; + } else { + return error_nil; + } + } + } + } +} +function decode2(cache, path, name2, event3) { + let parts = split_subtree_path(path + separator_event + name2); + let $ = get_handler(cache.events, parts, identity2); + if ($ instanceof Ok) { + let handler = $[0]; + let $1 = run(event3, handler); + if ($1 instanceof Ok) { + let handler$1 = $1[0]; + return new DecodedEvent(path, handler$1); + } else { + return new DispatchedEvent(path); + } + } else { + return new DispatchedEvent(path); + } +} +function dispatch(cache, event3) { + let next_dispatched_paths = prepend(event3.path, cache.next_dispatched_paths); + let cache$1 = new Cache(cache.events, cache.vdoms, cache.old_vdoms, cache.dispatched_paths, next_dispatched_paths); + if (event3 instanceof DecodedEvent) { + let handler = event3.handler; + return [cache$1, new Ok(handler)]; + } else { + return [cache$1, error_nil]; + } +} +function handle(cache, path, name2, event3) { + let _pipe = decode2(cache, path, name2, event3); + return ((_capture) => { + return dispatch(cache, _capture); + })(_pipe); +} +function has_dispatched_events(cache, path) { + return matches(path, cache.dispatched_paths); +} + +// build/dev/javascript/lustre/lustre/runtime/server/runtime.mjs +class ClientDispatchedMessage extends CustomType { + constructor(message) { + super(); + this.message = message; + } +} +var Message$isClientDispatchedMessage = (value2) => value2 instanceof ClientDispatchedMessage; +class ClientRegisteredCallback extends CustomType { + constructor(callback) { + super(); + this.callback = callback; + } +} +var Message$isClientRegisteredCallback = (value2) => value2 instanceof ClientRegisteredCallback; +class ClientDeregisteredCallback extends CustomType { + constructor(callback) { + super(); + this.callback = callback; + } +} +var Message$isClientDeregisteredCallback = (value2) => value2 instanceof ClientDeregisteredCallback; +class EffectDispatchedMessage extends CustomType { + constructor(message) { + super(); + this.message = message; + } +} +var Message$EffectDispatchedMessage = (message) => new EffectDispatchedMessage(message); +var Message$isEffectDispatchedMessage = (value2) => value2 instanceof EffectDispatchedMessage; +class EffectEmitEvent extends CustomType { + constructor(name2, data) { + super(); + this.name = name2; + this.data = data; + } +} +var Message$EffectEmitEvent = (name2, data) => new EffectEmitEvent(name2, data); +var Message$isEffectEmitEvent = (value2) => value2 instanceof EffectEmitEvent; +class EffectProvidedValue extends CustomType { + constructor(key, value2) { + super(); + this.key = key; + this.value = value2; + } +} +var Message$EffectProvidedValue = (key, value2) => new EffectProvidedValue(key, value2); +var Message$isEffectProvidedValue = (value2) => value2 instanceof EffectProvidedValue; +class EffectRequestedContextSubscription extends CustomType { + constructor(key, decoder) { + super(); + this.key = key; + this.decoder = decoder; + } +} +var Message$EffectRequestedContextSubscription = (key, decoder) => new EffectRequestedContextSubscription(key, decoder); +var Message$isEffectRequestedContextSubscription = (value2) => value2 instanceof EffectRequestedContextSubscription; +class EffectRemovedContextSubscription extends CustomType { + constructor(key) { + super(); + this.key = key; + } +} +var Message$EffectRemovedContextSubscription = (key) => new EffectRemovedContextSubscription(key); +var Message$isEffectRemovedContextSubscription = (value2) => value2 instanceof EffectRemovedContextSubscription; +class SystemRequestedShutdown extends CustomType { +} +var Message$SystemRequestedShutdown$const = new SystemRequestedShutdown; +var Message$isSystemRequestedShutdown = (value2) => value2 instanceof SystemRequestedShutdown; + +// build/dev/javascript/lustre/lustre/runtime/app.mjs +class App extends CustomType { + constructor(name2, init, update2, view, config) { + super(); + this.name = name2; + this.init = init; + this.update = update2; + this.view = view; + this.config = config; + } +} +class Config2 extends CustomType { + constructor(open_shadow_root, adopt_styles, delegates_focus, attributes, properties, contexts, is_form_associated, on_form_autofill, on_form_reset, on_form_restore, on_form_disabled, on_connect, on_adopt, on_disconnect) { + super(); + this.open_shadow_root = open_shadow_root; + this.adopt_styles = adopt_styles; + this.delegates_focus = delegates_focus; + this.attributes = attributes; + this.properties = properties; + this.contexts = contexts; + this.is_form_associated = is_form_associated; + this.on_form_autofill = on_form_autofill; + this.on_form_reset = on_form_reset; + this.on_form_restore = on_form_restore; + this.on_form_disabled = on_form_disabled; + this.on_connect = on_connect; + this.on_adopt = on_adopt; + this.on_disconnect = on_disconnect; + } +} +var default_config = /* @__PURE__ */ new Config2(true, true, false, empty_list, empty_list, empty_list, false, Option$None$const, Option$None$const, Option$None$const, Option$None$const, Option$None$const, Option$None$const, Option$None$const); + +// build/dev/javascript/lustre/lustre/internals/equals.ffi.mjs +var isEqual2 = (a2, b) => { + if (a2 === b) { + return true; + } + if (a2 == null || b == null) { + return false; + } + const type = typeof a2; + if (type !== typeof b) { + return false; + } + if (type !== "object") { + return false; + } + const ctor = a2.constructor; + if (ctor !== b.constructor) { + return false; + } + if (Array.isArray(a2)) { + return areArraysEqual(a2, b); + } + return areObjectsEqual(a2, b); +}; +var areArraysEqual = (a2, b) => { + let index4 = a2.length; + if (index4 !== b.length) { + return false; + } + while (index4--) { + if (!isEqual2(a2[index4], b[index4])) { + return false; + } + } + return true; +}; +var areObjectsEqual = (a2, b) => { + const properties = Object.keys(a2); + let index4 = properties.length; + if (Object.keys(b).length !== index4) { + return false; + } + while (index4--) { + const property3 = properties[index4]; + if (!Object.hasOwn(b, property3)) { + return false; + } + if (!isEqual2(a2[property3], b[property3])) { + return false; + } + } + return true; +}; + +// build/dev/javascript/lustre/lustre/vdom/diff.mjs +class Diff extends CustomType { + constructor(patch, cache) { + super(); + this.patch = patch; + this.cache = cache; + } +} +class PartialDiff extends CustomType { + constructor(patch, cache, events2) { + super(); + this.patch = patch; + this.cache = cache; + this.events = events2; + } +} + +class AttributeChange extends CustomType { + constructor(added, removed, events2) { + super(); + this.added = added; + this.removed = removed; + this.events = events2; + } +} +function diff_attributes(loop$controlled, loop$path, loop$events, loop$old, loop$new, loop$added, loop$removed) { + while (true) { + let controlled = loop$controlled; + let path = loop$path; + let events2 = loop$events; + let old = loop$old; + let new$5 = loop$new; + let added = loop$added; + let removed = loop$removed; + if (old instanceof Empty) { + if (new$5 instanceof Empty) { + return new AttributeChange(added, removed, events2); + } else { + let $ = new$5.head; + if ($ instanceof Event2) { + let next = $; + let new$1 = new$5.tail; + let name2 = $.name; + let handler = $.handler; + let events$1 = add_event(events2, path, name2, handler); + let added$1 = prepend(next, added); + loop$controlled = controlled; + loop$path = path; + loop$events = events$1; + loop$old = old; + loop$new = new$1; + loop$added = added$1; + loop$removed = removed; + } else { + let next = $; + let new$1 = new$5.tail; + let added$1 = prepend(next, added); + loop$controlled = controlled; + loop$path = path; + loop$events = events2; + loop$old = old; + loop$new = new$1; + loop$added = added$1; + loop$removed = removed; + } + } + } else if (new$5 instanceof Empty) { + let $ = old.head; + if ($ instanceof Event2) { + let prev = $; + let old$1 = old.tail; + let name2 = $.name; + let events$1 = remove_event(events2, path, name2); + let removed$1 = prepend(prev, removed); + loop$controlled = controlled; + loop$path = path; + loop$events = events$1; + loop$old = old$1; + loop$new = new$5; + loop$added = added; + loop$removed = removed$1; + } else { + let prev = $; + let old$1 = old.tail; + let removed$1 = prepend(prev, removed); + loop$controlled = controlled; + loop$path = path; + loop$events = events2; + loop$old = old$1; + loop$new = new$5; + loop$added = added; + loop$removed = removed$1; + } + } else { + let prev = old.head; + let remaining_old = old.tail; + let next = new$5.head; + let remaining_new = new$5.tail; + let $ = compare2(prev, next); + if ($ instanceof Lt) { + if (prev instanceof Event2) { + let name2 = prev.name; + loop$controlled = controlled; + loop$path = path; + loop$events = remove_event(events2, path, name2); + loop$old = remaining_old; + loop$new = new$5; + loop$added = added; + loop$removed = prepend(prev, removed); + } else { + loop$controlled = controlled; + loop$path = path; + loop$events = events2; + loop$old = remaining_old; + loop$new = new$5; + loop$added = added; + loop$removed = prepend(prev, removed); + } + } else if ($ instanceof Eq) { + if (prev instanceof Attribute) { + if (next instanceof Attribute) { + let _block; + let $1 = next.name; + if ($1 === "value") { + _block = controlled || prev.value !== next.value; + } else if ($1 === "checked") { + _block = controlled || prev.value !== next.value; + } else if ($1 === "selected") { + _block = controlled || prev.value !== next.value; + } else { + _block = prev.value !== next.value; + } + let has_changes = _block; + let _block$1; + if (has_changes) { + _block$1 = prepend(next, added); + } else { + _block$1 = added; + } + let added$1 = _block$1; + loop$controlled = controlled; + loop$path = path; + loop$events = events2; + loop$old = remaining_old; + loop$new = remaining_new; + loop$added = added$1; + loop$removed = removed; + } else if (next instanceof Event2) { + let name2 = next.name; + let handler = next.handler; + loop$controlled = controlled; + loop$path = path; + loop$events = add_event(events2, path, name2, handler); + loop$old = remaining_old; + loop$new = remaining_new; + loop$added = prepend(next, added); + loop$removed = prepend(prev, removed); + } else { + loop$controlled = controlled; + loop$path = path; + loop$events = events2; + loop$old = remaining_old; + loop$new = remaining_new; + loop$added = prepend(next, added); + loop$removed = prepend(prev, removed); + } + } else if (prev instanceof Property) { + if (next instanceof Property) { + let _block; + let $1 = next.name; + if ($1 === "scrollLeft") { + _block = true; + } else if ($1 === "scrollRight") { + _block = true; + } else if ($1 === "value") { + _block = controlled || !isEqual2(prev.value, next.value); + } else if ($1 === "checked") { + _block = controlled || !isEqual2(prev.value, next.value); + } else if ($1 === "selected") { + _block = controlled || !isEqual2(prev.value, next.value); + } else { + _block = !isEqual2(prev.value, next.value); + } + let has_changes = _block; + let _block$1; + if (has_changes) { + _block$1 = prepend(next, added); + } else { + _block$1 = added; + } + let added$1 = _block$1; + loop$controlled = controlled; + loop$path = path; + loop$events = events2; + loop$old = remaining_old; + loop$new = remaining_new; + loop$added = added$1; + loop$removed = removed; + } else if (next instanceof Event2) { + let name2 = next.name; + let handler = next.handler; + loop$controlled = controlled; + loop$path = path; + loop$events = add_event(events2, path, name2, handler); + loop$old = remaining_old; + loop$new = remaining_new; + loop$added = prepend(next, added); + loop$removed = prepend(prev, removed); + } else { + loop$controlled = controlled; + loop$path = path; + loop$events = events2; + loop$old = remaining_old; + loop$new = remaining_new; + loop$added = prepend(next, added); + loop$removed = prepend(prev, removed); + } + } else if (next instanceof Event2) { + let name2 = next.name; + let handler = next.handler; + let has_changes = prev.prevent_default.kind !== next.prevent_default.kind || prev.stop_propagation.kind !== next.stop_propagation.kind || prev.debounce !== next.debounce || prev.throttle !== next.throttle; + let _block; + if (has_changes) { + _block = prepend(next, added); + } else { + _block = added; + } + let added$1 = _block; + loop$controlled = controlled; + loop$path = path; + loop$events = add_event(events2, path, name2, handler); + loop$old = remaining_old; + loop$new = remaining_new; + loop$added = added$1; + loop$removed = removed; + } else { + let name2 = prev.name; + loop$controlled = controlled; + loop$path = path; + loop$events = remove_event(events2, path, name2); + loop$old = remaining_old; + loop$new = remaining_new; + loop$added = prepend(next, added); + loop$removed = prepend(prev, removed); + } + } else if (next instanceof Event2) { + let name2 = next.name; + let handler = next.handler; + loop$controlled = controlled; + loop$path = path; + loop$events = add_event(events2, path, name2, handler); + loop$old = old; + loop$new = remaining_new; + loop$added = prepend(next, added); + loop$removed = removed; + } else { + loop$controlled = controlled; + loop$path = path; + loop$events = events2; + loop$old = old; + loop$new = remaining_new; + loop$added = prepend(next, added); + loop$removed = removed; + } + } + } +} +function is_controlled(cache, namespace, tag, path) { + if (tag === "input" && namespace === "") { + return has_dispatched_events(cache, path); + } else if (tag === "select" && namespace === "") { + return has_dispatched_events(cache, path); + } else if (tag === "textarea" && namespace === "") { + return has_dispatched_events(cache, path); + } else { + return false; + } +} +function do_diff(loop$old, loop$old_keyed, loop$new, loop$new_keyed, loop$moved, loop$moved_offset, loop$removed, loop$node_index, loop$patch_index, loop$changes, loop$children, loop$path, loop$cache, loop$events) { + while (true) { + let old = loop$old; + let old_keyed = loop$old_keyed; + let new$5 = loop$new; + let new_keyed = loop$new_keyed; + let moved = loop$moved; + let moved_offset = loop$moved_offset; + let removed = loop$removed; + let node_index = loop$node_index; + let patch_index = loop$patch_index; + let changes = loop$changes; + let children = loop$children; + let path = loop$path; + let cache = loop$cache; + let events2 = loop$events; + if (old instanceof Empty) { + if (new$5 instanceof Empty) { + let _block; + let $ = is_browser(); + if (changes instanceof Empty) { + if (children instanceof Empty) { + _block = new$3(patch_index, removed, changes, children); + } else if (!$) { + let $1 = children.tail; + if ($1 instanceof Empty && removed === 0) { + let child2 = children.head; + _block = add_parent(child2, patch_index); + } else { + _block = new$3(patch_index, removed, changes, children); + } + } else { + _block = new$3(patch_index, removed, changes, children); + } + } else { + _block = new$3(patch_index, removed, changes, children); + } + let patch = _block; + return new PartialDiff(patch, cache, events2); + } else { + let $ = add_children(cache, events2, path, node_index, new$5); + let cache$1 = $[0]; + let events$1 = $[1]; + let insert4 = insert3(new$5, node_index - moved_offset); + let changes$1 = prepend(insert4, changes); + let patch = new$3(patch_index, removed, changes$1, children); + return new PartialDiff(patch, cache$1, events$1); + } + } else if (new$5 instanceof Empty) { + let prev = old.head; + let old$1 = old.tail; + let $ = prev.key === "" || !has_key(moved, prev.key); + if ($) { + let events$1 = remove_child(cache, events2, path, node_index, prev); + loop$old = old$1; + loop$old_keyed = old_keyed; + loop$new = new$5; + loop$new_keyed = new_keyed; + loop$moved = moved; + loop$moved_offset = moved_offset; + loop$removed = removed + 1; + loop$node_index = node_index; + loop$patch_index = patch_index; + loop$changes = changes; + loop$children = children; + loop$path = path; + loop$cache = cache; + loop$events = events$1; + } else { + loop$old = old$1; + loop$old_keyed = old_keyed; + loop$new = new$5; + loop$new_keyed = new_keyed; + loop$moved = moved; + loop$moved_offset = moved_offset; + loop$removed = removed; + loop$node_index = node_index; + loop$patch_index = patch_index; + loop$changes = changes; + loop$children = children; + loop$path = path; + loop$cache = cache; + loop$events = events2; + } + } else { + let prev = old.head; + let next = new$5.head; + if (prev.key !== next.key) { + let old_remaining = old.tail; + let new_remaining = new$5.tail; + let next_did_exist = has_key(old_keyed, next.key); + let prev_does_exist = has_key(new_keyed, prev.key); + if (prev_does_exist) { + if (next_did_exist) { + let $ = has_key(moved, prev.key); + if ($) { + loop$old = old_remaining; + loop$old_keyed = old_keyed; + loop$new = new$5; + loop$new_keyed = new_keyed; + loop$moved = moved; + loop$moved_offset = moved_offset - 1; + loop$removed = removed; + loop$node_index = node_index; + loop$patch_index = patch_index; + loop$changes = changes; + loop$children = children; + loop$path = path; + loop$cache = cache; + loop$events = events2; + } else { + let match = get2(old_keyed, next.key); + let before = node_index - moved_offset; + let changes$1 = prepend(move(next.key, before), changes); + let moved$1 = insert2(moved, next.key, undefined); + loop$old = prepend(match, old); + loop$old_keyed = old_keyed; + loop$new = new$5; + loop$new_keyed = new_keyed; + loop$moved = moved$1; + loop$moved_offset = moved_offset + 1; + loop$removed = removed; + loop$node_index = node_index; + loop$patch_index = patch_index; + loop$changes = changes$1; + loop$children = children; + loop$path = path; + loop$cache = cache; + loop$events = events2; + } + } else { + let before = node_index - moved_offset; + let $ = add_child(cache, events2, path, node_index, next); + let cache$1 = $[0]; + let events$1 = $[1]; + let insert4 = insert3(singleton_list(next), before); + let changes$1 = prepend(insert4, changes); + loop$old = old; + loop$old_keyed = old_keyed; + loop$new = new_remaining; + loop$new_keyed = new_keyed; + loop$moved = moved; + loop$moved_offset = moved_offset + 1; + loop$removed = removed; + loop$node_index = node_index + 1; + loop$patch_index = patch_index; + loop$changes = changes$1; + loop$children = children; + loop$path = path; + loop$cache = cache$1; + loop$events = events$1; + } + } else if (next_did_exist) { + let index4 = node_index - moved_offset; + let changes$1 = prepend(remove2(index4), changes); + let events$1 = remove_child(cache, events2, path, node_index, prev); + loop$old = old_remaining; + loop$old_keyed = old_keyed; + loop$new = new$5; + loop$new_keyed = new_keyed; + loop$moved = moved; + loop$moved_offset = moved_offset - 1; + loop$removed = removed; + loop$node_index = node_index; + loop$patch_index = patch_index; + loop$changes = changes$1; + loop$children = children; + loop$path = path; + loop$cache = cache; + loop$events = events$1; + } else { + let change = replace2(node_index - moved_offset, next); + let $ = replace_child(cache, events2, path, node_index, prev, next); + let cache$1 = $[0]; + let events$1 = $[1]; + loop$old = old_remaining; + loop$old_keyed = old_keyed; + loop$new = new_remaining; + loop$new_keyed = new_keyed; + loop$moved = moved; + loop$moved_offset = moved_offset; + loop$removed = removed; + loop$node_index = node_index + 1; + loop$patch_index = patch_index; + loop$changes = prepend(change, changes); + loop$children = children; + loop$path = path; + loop$cache = cache$1; + loop$events = events$1; + } + } else { + let $ = old.head; + if ($ instanceof Fragment) { + let $1 = new$5.head; + if ($1 instanceof Fragment) { + let prev2 = $; + let old$1 = old.tail; + let next2 = $1; + let new$1 = new$5.tail; + let $2 = do_diff(prev2.children, prev2.keyed_children, next2.children, next2.keyed_children, empty2(), 0, 0, 0, node_index, empty_list, empty_list, add2(path, node_index, next2.key), cache, events2); + let patch = $2.patch; + let cache$1 = $2.cache; + let events$1 = $2.events; + let _block; + let $3 = patch.changes; + if ($3 instanceof Empty) { + let $4 = patch.children; + if ($4 instanceof Empty) { + let $5 = patch.removed; + if ($5 === 0) { + _block = children; + } else { + _block = prepend(patch, children); + } + } else { + _block = prepend(patch, children); + } + } else { + _block = prepend(patch, children); + } + let children$1 = _block; + loop$old = old$1; + loop$old_keyed = old_keyed; + loop$new = new$1; + loop$new_keyed = new_keyed; + loop$moved = moved; + loop$moved_offset = moved_offset; + loop$removed = removed; + loop$node_index = node_index + 1; + loop$patch_index = patch_index; + loop$changes = changes; + loop$children = children$1; + loop$path = path; + loop$cache = cache$1; + loop$events = events$1; + } else { + let prev2 = $; + let old_remaining = old.tail; + let next2 = $1; + let new_remaining = new$5.tail; + let change = replace2(node_index - moved_offset, next2); + let $2 = replace_child(cache, events2, path, node_index, prev2, next2); + let cache$1 = $2[0]; + let events$1 = $2[1]; + loop$old = old_remaining; + loop$old_keyed = old_keyed; + loop$new = new_remaining; + loop$new_keyed = new_keyed; + loop$moved = moved; + loop$moved_offset = moved_offset; + loop$removed = removed; + loop$node_index = node_index + 1; + loop$patch_index = patch_index; + loop$changes = prepend(change, changes); + loop$children = children; + loop$path = path; + loop$cache = cache$1; + loop$events = events$1; + } + } else if ($ instanceof Element2) { + let $1 = new$5.head; + if ($1 instanceof Element2) { + let prev2 = $; + let next2 = $1; + if (prev2.namespace === next2.namespace && prev2.tag === next2.tag) { + let old$1 = old.tail; + let new$1 = new$5.tail; + let child_path = add2(path, node_index, next2.key); + let controlled = is_controlled(cache, next2.namespace, next2.tag, child_path); + let $2 = diff_attributes(controlled, child_path, events2, prev2.attributes, next2.attributes, empty_list, empty_list); + let added_attrs = $2.added; + let removed_attrs = $2.removed; + let events$1 = $2.events; + let _block; + if (added_attrs instanceof Empty && removed_attrs instanceof Empty) { + _block = empty_list; + } else { + _block = singleton_list(update(added_attrs, removed_attrs)); + } + let initial_child_changes = _block; + let $3 = do_diff(prev2.children, prev2.keyed_children, next2.children, next2.keyed_children, empty2(), 0, 0, 0, node_index, initial_child_changes, empty_list, child_path, cache, events$1); + let patch = $3.patch; + let cache$1 = $3.cache; + let events$2 = $3.events; + let _block$1; + let $4 = patch.changes; + if ($4 instanceof Empty) { + let $5 = patch.children; + if ($5 instanceof Empty) { + let $6 = patch.removed; + if ($6 === 0) { + _block$1 = children; + } else { + _block$1 = prepend(patch, children); + } + } else { + _block$1 = prepend(patch, children); + } + } else { + _block$1 = prepend(patch, children); + } + let children$1 = _block$1; + loop$old = old$1; + loop$old_keyed = old_keyed; + loop$new = new$1; + loop$new_keyed = new_keyed; + loop$moved = moved; + loop$moved_offset = moved_offset; + loop$removed = removed; + loop$node_index = node_index + 1; + loop$patch_index = patch_index; + loop$changes = changes; + loop$children = children$1; + loop$path = path; + loop$cache = cache$1; + loop$events = events$2; + } else { + let prev3 = $; + let old_remaining = old.tail; + let next3 = $1; + let new_remaining = new$5.tail; + let change = replace2(node_index - moved_offset, next3); + let $2 = replace_child(cache, events2, path, node_index, prev3, next3); + let cache$1 = $2[0]; + let events$1 = $2[1]; + loop$old = old_remaining; + loop$old_keyed = old_keyed; + loop$new = new_remaining; + loop$new_keyed = new_keyed; + loop$moved = moved; + loop$moved_offset = moved_offset; + loop$removed = removed; + loop$node_index = node_index + 1; + loop$patch_index = patch_index; + loop$changes = prepend(change, changes); + loop$children = children; + loop$path = path; + loop$cache = cache$1; + loop$events = events$1; + } + } else { + let prev2 = $; + let old_remaining = old.tail; + let next2 = $1; + let new_remaining = new$5.tail; + let change = replace2(node_index - moved_offset, next2); + let $2 = replace_child(cache, events2, path, node_index, prev2, next2); + let cache$1 = $2[0]; + let events$1 = $2[1]; + loop$old = old_remaining; + loop$old_keyed = old_keyed; + loop$new = new_remaining; + loop$new_keyed = new_keyed; + loop$moved = moved; + loop$moved_offset = moved_offset; + loop$removed = removed; + loop$node_index = node_index + 1; + loop$patch_index = patch_index; + loop$changes = prepend(change, changes); + loop$children = children; + loop$path = path; + loop$cache = cache$1; + loop$events = events$1; + } + } else if ($ instanceof Text) { + let $1 = new$5.head; + if ($1 instanceof Text) { + let prev2 = $; + let next2 = $1; + if (prev2.content === next2.content) { + let old$1 = old.tail; + let new$1 = new$5.tail; + loop$old = old$1; + loop$old_keyed = old_keyed; + loop$new = new$1; + loop$new_keyed = new_keyed; + loop$moved = moved; + loop$moved_offset = moved_offset; + loop$removed = removed; + loop$node_index = node_index + 1; + loop$patch_index = patch_index; + loop$changes = changes; + loop$children = children; + loop$path = path; + loop$cache = cache; + loop$events = events2; + } else { + let old$1 = old.tail; + let next3 = $1; + let new$1 = new$5.tail; + let child2 = new$3(node_index, 0, singleton_list(replace_text(next3.content)), empty_list); + loop$old = old$1; + loop$old_keyed = old_keyed; + loop$new = new$1; + loop$new_keyed = new_keyed; + loop$moved = moved; + loop$moved_offset = moved_offset; + loop$removed = removed; + loop$node_index = node_index + 1; + loop$patch_index = patch_index; + loop$changes = changes; + loop$children = prepend(child2, children); + loop$path = path; + loop$cache = cache; + loop$events = events2; + } + } else { + let prev2 = $; + let old_remaining = old.tail; + let next2 = $1; + let new_remaining = new$5.tail; + let change = replace2(node_index - moved_offset, next2); + let $2 = replace_child(cache, events2, path, node_index, prev2, next2); + let cache$1 = $2[0]; + let events$1 = $2[1]; + loop$old = old_remaining; + loop$old_keyed = old_keyed; + loop$new = new_remaining; + loop$new_keyed = new_keyed; + loop$moved = moved; + loop$moved_offset = moved_offset; + loop$removed = removed; + loop$node_index = node_index + 1; + loop$patch_index = patch_index; + loop$changes = prepend(change, changes); + loop$children = children; + loop$path = path; + loop$cache = cache$1; + loop$events = events$1; + } + } else if ($ instanceof UnsafeInnerHtml) { + let $1 = new$5.head; + if ($1 instanceof UnsafeInnerHtml) { + let prev2 = $; + let old$1 = old.tail; + let next2 = $1; + let new$1 = new$5.tail; + let child_path = add2(path, node_index, next2.key); + let $2 = diff_attributes(false, child_path, events2, prev2.attributes, next2.attributes, empty_list, empty_list); + let added_attrs = $2.added; + let removed_attrs = $2.removed; + let events$1 = $2.events; + let _block; + if (added_attrs instanceof Empty && removed_attrs instanceof Empty) { + _block = empty_list; + } else { + _block = singleton_list(update(added_attrs, removed_attrs)); + } + let child_changes = _block; + let _block$1; + let $3 = prev2.inner_html === next2.inner_html; + if ($3) { + _block$1 = child_changes; + } else { + _block$1 = prepend(replace_inner_html(next2.inner_html), child_changes); + } + let child_changes$1 = _block$1; + let _block$2; + if (child_changes$1 instanceof Empty) { + _block$2 = children; + } else { + _block$2 = prepend(new$3(node_index, 0, child_changes$1, empty_list), children); + } + let children$1 = _block$2; + loop$old = old$1; + loop$old_keyed = old_keyed; + loop$new = new$1; + loop$new_keyed = new_keyed; + loop$moved = moved; + loop$moved_offset = moved_offset; + loop$removed = removed; + loop$node_index = node_index + 1; + loop$patch_index = patch_index; + loop$changes = changes; + loop$children = children$1; + loop$path = path; + loop$cache = cache; + loop$events = events$1; + } else { + let prev2 = $; + let old_remaining = old.tail; + let next2 = $1; + let new_remaining = new$5.tail; + let change = replace2(node_index - moved_offset, next2); + let $2 = replace_child(cache, events2, path, node_index, prev2, next2); + let cache$1 = $2[0]; + let events$1 = $2[1]; + loop$old = old_remaining; + loop$old_keyed = old_keyed; + loop$new = new_remaining; + loop$new_keyed = new_keyed; + loop$moved = moved; + loop$moved_offset = moved_offset; + loop$removed = removed; + loop$node_index = node_index + 1; + loop$patch_index = patch_index; + loop$changes = prepend(change, changes); + loop$children = children; + loop$path = path; + loop$cache = cache$1; + loop$events = events$1; + } + } else if ($ instanceof Map2) { + let $1 = new$5.head; + if ($1 instanceof Map2) { + let prev2 = $; + let old$1 = old.tail; + let next2 = $1; + let new$1 = new$5.tail; + let child_path = add2(path, node_index, next2.key); + let child_key = child(child_path); + let $2 = do_diff(singleton_list(prev2.child), empty2(), singleton_list(next2.child), empty2(), empty2(), 0, 0, 0, node_index, empty_list, empty_list, subtree(child_path), cache, get_subtree(events2, child_key, prev2.mapper)); + let patch = $2.patch; + let cache$1 = $2.cache; + let child_events = $2.events; + let events$1 = update_subtree(events2, child_key, next2.mapper, child_events); + let _block; + let $3 = patch.changes; + if ($3 instanceof Empty) { + let $4 = patch.children; + if ($4 instanceof Empty) { + let $5 = patch.removed; + if ($5 === 0) { + _block = children; + } else { + _block = prepend(patch, children); + } + } else { + _block = prepend(patch, children); + } + } else { + _block = prepend(patch, children); + } + let children$1 = _block; + loop$old = old$1; + loop$old_keyed = old_keyed; + loop$new = new$1; + loop$new_keyed = new_keyed; + loop$moved = moved; + loop$moved_offset = moved_offset; + loop$removed = removed; + loop$node_index = node_index + 1; + loop$patch_index = patch_index; + loop$changes = changes; + loop$children = children$1; + loop$path = path; + loop$cache = cache$1; + loop$events = events$1; + } else { + let prev2 = $; + let old_remaining = old.tail; + let next2 = $1; + let new_remaining = new$5.tail; + let change = replace2(node_index - moved_offset, next2); + let $2 = replace_child(cache, events2, path, node_index, prev2, next2); + let cache$1 = $2[0]; + let events$1 = $2[1]; + loop$old = old_remaining; + loop$old_keyed = old_keyed; + loop$new = new_remaining; + loop$new_keyed = new_keyed; + loop$moved = moved; + loop$moved_offset = moved_offset; + loop$removed = removed; + loop$node_index = node_index + 1; + loop$patch_index = patch_index; + loop$changes = prepend(change, changes); + loop$children = children; + loop$path = path; + loop$cache = cache$1; + loop$events = events$1; + } + } else { + let $1 = new$5.head; + if ($1 instanceof Memo) { + let prev2 = $; + let old$1 = old.tail; + let next2 = $1; + let new$1 = new$5.tail; + let $2 = equal_lists(prev2.dependencies, next2.dependencies); + if ($2) { + let cache$1 = keep_memo(cache, prev2.view, next2.view); + loop$old = old$1; + loop$old_keyed = old_keyed; + loop$new = new$1; + loop$new_keyed = new_keyed; + loop$moved = moved; + loop$moved_offset = moved_offset; + loop$removed = removed; + loop$node_index = node_index + 1; + loop$patch_index = patch_index; + loop$changes = changes; + loop$children = children; + loop$path = path; + loop$cache = cache$1; + loop$events = events2; + } else { + let prev_node = get_old_memo(cache, prev2.view, prev2.view); + let next_node = next2.view(); + let cache$1 = add_memo(cache, next2.view, next_node); + loop$old = prepend(prev_node, old$1); + loop$old_keyed = old_keyed; + loop$new = prepend(next_node, new$1); + loop$new_keyed = new_keyed; + loop$moved = moved; + loop$moved_offset = moved_offset; + loop$removed = removed; + loop$node_index = node_index; + loop$patch_index = patch_index; + loop$changes = changes; + loop$children = children; + loop$path = path; + loop$cache = cache$1; + loop$events = events2; + } + } else { + let prev2 = $; + let old_remaining = old.tail; + let next2 = $1; + let new_remaining = new$5.tail; + let change = replace2(node_index - moved_offset, next2); + let $2 = replace_child(cache, events2, path, node_index, prev2, next2); + let cache$1 = $2[0]; + let events$1 = $2[1]; + loop$old = old_remaining; + loop$old_keyed = old_keyed; + loop$new = new_remaining; + loop$new_keyed = new_keyed; + loop$moved = moved; + loop$moved_offset = moved_offset; + loop$removed = removed; + loop$node_index = node_index + 1; + loop$patch_index = patch_index; + loop$changes = prepend(change, changes); + loop$children = children; + loop$path = path; + loop$cache = cache$1; + loop$events = events$1; + } + } + } + } + } +} +function diff(cache, old, new$5) { + let cache$1 = tick(cache); + let $ = do_diff(singleton_list(old), empty2(), singleton_list(new$5), empty2(), empty2(), 0, 0, 0, 0, empty_list, empty_list, root, cache$1, events(cache$1)); + let patch = $.patch; + let cache$2 = $.cache; + let events2 = $.events; + return new Diff(patch, update_events(cache$2, events2)); +} + +// build/dev/javascript/lustre/lustre/internals/list.ffi.mjs +var toList2 = (arr) => arr.reduceRight((xs, x) => List$NonEmpty(x, xs), empty_list); +var iterate = (list4, callback) => { + if (Array.isArray(list4)) { + for (let i = 0;i < list4.length; i++) { + callback(list4[i]); + } + } else if (list4) { + for (list4;List$NonEmpty$rest(list4); list4 = List$NonEmpty$rest(list4)) { + callback(List$NonEmpty$first(list4)); + } + } +}; +var append4 = (a2, b) => { + if (!List$NonEmpty$rest(a2)) { + return b; + } else if (!List$NonEmpty$rest(b)) { + return a2; + } else { + return append(a2, b); + } +}; + +// build/dev/javascript/lustre/lustre/internals/constants.ffi.mjs +var NAMESPACE_HTML = "http://www.w3.org/1999/xhtml"; +var ELEMENT_NODE = 1; +var TEXT_NODE = 3; +var COMMENT_NODE = 8; +var SUPPORTS_MOVE_BEFORE = !!globalThis.HTMLElement?.prototype?.moveBefore; + +// build/dev/javascript/lustre/lustre/vdom/reconciler.ffi.mjs +var setTimeout = globalThis.setTimeout; +var clearTimeout = globalThis.clearTimeout; +var createElementNS = (ns, name2) => globalThis.document.createElementNS(ns, name2); +var createTextNode = (data) => globalThis.document.createTextNode(data); +var createComment = (data) => globalThis.document.createComment(data); +var createDocumentFragment = () => globalThis.document.createDocumentFragment(); +var insertBefore = (parent, node, reference) => parent.insertBefore(node, reference); +var moveBefore = SUPPORTS_MOVE_BEFORE ? (parent, node, reference) => parent.moveBefore(node, reference) : insertBefore; +var removeChild = (parent, child2) => parent.removeChild(child2); +var getAttribute = (node, name2) => node.getAttribute(name2); +var setAttribute = (node, name2, value2) => node.setAttribute(name2, value2); +var removeAttribute = (node, name2) => node.removeAttribute(name2); +var addEventListener = (node, name2, handler, options) => node.addEventListener(name2, handler, options); +var removeEventListener = (node, name2, handler) => node.removeEventListener(name2, handler); +var setInnerHtml = (node, innerHtml) => node.innerHTML = innerHtml; +var setData = (node, data) => node.data = data; +var meta = Symbol("lustre"); + +class MetadataNode { + constructor(kind, parent, node, key) { + this.kind = kind; + this.key = key; + this.parent = parent; + this.children = []; + this.node = node; + this.endNode = null; + this.handlers = new Map; + this.throttles = new Map; + this.debouncers = new Map; + } + get isVirtual() { + return this.kind === fragment_kind || this.kind === map_kind; + } + get parentNode() { + return this.isVirtual ? this.node.parentNode : this.node; + } +} +var insertMetadataChild = (kind, parent, node, index4, key) => { + const child2 = new MetadataNode(kind, parent, node, key); + node[meta] = child2; + parent?.children.splice(index4, 0, child2); + return child2; +}; +var getPath = (node) => { + let path = ""; + for (let current = node[meta];current.parent; current = current.parent) { + const separator = current.parent && current.parent.kind === map_kind ? separator_subtree : separator_element; + if (current.key) { + path = `${separator}${current.key}${path}`; + } else { + const index4 = current.parent.children.indexOf(current); + path = `${separator}${index4}${path}`; + } + } + return path.slice(1); +}; + +class Reconciler { + #root = null; + #decodeEvent; + #dispatch; + #debug = false; + constructor(root2, decodeEvent, dispatch2, { debug = false } = {}) { + this.#root = root2; + this.#decodeEvent = decodeEvent; + this.#dispatch = dispatch2; + this.#debug = debug; + } + mount(vdom) { + insertMetadataChild(element_kind, null, this.#root, 0, null); + this.#insertChild(this.#root, null, this.#root[meta], 0, vdom); + } + push(patch, memos2 = null) { + this.#memos = memos2; + this.#stack.push({ node: this.#root[meta], patch }); + this.#reconcile(); + } + #memos; + #stack = []; + #reconcile() { + const stack = this.#stack; + while (stack.length) { + let { node, patch } = stack.pop(); + const { path, changes, removed, children: childPatches } = patch; + iterate(path, (index4) => { + node = node.children[index4]; + }); + const { children: childNodes } = node; + iterate(changes, (change) => this.#patch(node, change)); + if (removed) { + this.#removeChildren(node, childNodes.length - removed, removed); + } + iterate(childPatches, (childPatch) => { + const child2 = childNodes[childPatch.index | 0]; + this.#stack.push({ node: child2, patch: childPatch }); + }); + } + } + #patch(node, change) { + switch (change.kind) { + case replace_text_kind: + this.#replaceText(node, change); + break; + case replace_inner_html_kind: + this.#replaceInnerHtml(node, change); + break; + case update_kind: + this.#update(node, change); + break; + case move_kind: + this.#move(node, change); + break; + case remove_kind: + this.#remove(node, change); + break; + case replace_kind: + this.#replace(node, change); + break; + case insert_kind: + this.#insert(node, change); + break; + } + } + #insert(parent, { children, before }) { + const fragment2 = createDocumentFragment(); + const beforeEl = this.#getReference(parent, before); + this.#insertChildren(fragment2, null, parent, before | 0, children); + insertBefore(parent.parentNode, fragment2, beforeEl); + } + #replace(parent, { index: index4, with: child2 }) { + this.#removeChildren(parent, index4 | 0, 1); + const beforeEl = this.#getReference(parent, index4); + this.#insertChild(parent.parentNode, beforeEl, parent, index4 | 0, child2); + } + #getReference(node, index4) { + index4 = index4 | 0; + const { children } = node; + const childCount = children.length; + if (index4 < childCount) + return children[index4].node; + if (node.endNode) + return node.endNode; + if (!node.isVirtual) + return null; + while (node.isVirtual && node.children.length) { + if (node.endNode) + return node.endNode.nextSibling; + node = node.children[node.children.length - 1]; + } + return node.node.nextSibling; + } + #move(parent, { key, before }) { + before = before | 0; + const { children, parentNode } = parent; + const beforeEl = children[before].node; + let prev = children[before]; + for (let i = before + 1;i < children.length; ++i) { + const next = children[i]; + children[i] = prev; + prev = next; + if (next.key === key) { + children[before] = next; + break; + } + } + this.#moveChild(parentNode, prev, beforeEl); + } + #moveChildren(domParent, children, beforeEl) { + for (let i = 0;i < children.length; ++i) { + this.#moveChild(domParent, children[i], beforeEl); + } + } + #moveChild(domParent, child2, beforeEl) { + moveBefore(domParent, child2.node, beforeEl); + if (child2.isVirtual) { + this.#moveChildren(domParent, child2.children, beforeEl); + } + if (child2.endNode) { + moveBefore(domParent, child2.endNode, beforeEl); + } + } + #remove(parent, { index: index4 }) { + this.#removeChildren(parent, index4, 1); + } + #removeChildren(parent, index4, count) { + const { children, parentNode } = parent; + const deleted = children.splice(index4, count); + for (let i = 0;i < deleted.length; ++i) { + const child2 = deleted[i]; + const { node, endNode, isVirtual, children: nestedChildren } = child2; + removeChild(parentNode, node); + if (endNode) { + removeChild(parentNode, endNode); + } + this.#removeDebouncers(child2); + if (isVirtual) { + deleted.push(...nestedChildren); + } + } + } + #removeDebouncers(node) { + const { debouncers, children } = node; + for (const { timeout } of debouncers.values()) { + if (timeout) { + clearTimeout(timeout); + } + } + debouncers.clear(); + iterate(children, (child2) => this.#removeDebouncers(child2)); + } + #update({ node, handlers, throttles, debouncers }, { added, removed }) { + iterate(removed, ({ name: name2 }) => { + if (handlers.delete(name2)) { + removeEventListener(node, name2, handleEvent); + this.#updateDebounceThrottle(throttles, name2, 0); + this.#updateDebounceThrottle(debouncers, name2, 0); + } else { + removeAttribute(node, name2); + SYNCED_ATTRIBUTES[name2]?.removed?.(node, name2); + } + }); + iterate(added, (attribute3) => this.#createAttribute(node, attribute3)); + } + #replaceText({ node }, { content }) { + setData(node, content ?? ""); + } + #replaceInnerHtml({ node }, { inner_html }) { + setInnerHtml(node, inner_html ?? ""); + } + #insertChildren(domParent, beforeEl, metaParent, index4, children) { + iterate(children, (child2) => this.#insertChild(domParent, beforeEl, metaParent, index4++, child2)); + } + #insertChild(domParent, beforeEl, metaParent, index4, vnode) { + switch (vnode.kind) { + case element_kind: { + const node = this.#createElement(metaParent, index4, vnode); + this.#insertChildren(node, null, node[meta], 0, vnode.children); + insertBefore(domParent, node, beforeEl); + break; + } + case text_kind: { + const node = this.#createTextNode(metaParent, index4, vnode); + insertBefore(domParent, node, beforeEl); + break; + } + case fragment_kind: { + const marker = "lustre:fragment"; + const head = this.#createHead(marker, metaParent, index4, vnode); + insertBefore(domParent, head, beforeEl); + this.#insertChildren(domParent, beforeEl, head[meta], 0, vnode.children); + if (this.#debug) { + head[meta].endNode = createComment(` /${marker} `); + insertBefore(domParent, head[meta].endNode, beforeEl); + } + break; + } + case unsafe_inner_html_kind: { + const node = this.#createElement(metaParent, index4, vnode); + this.#replaceInnerHtml({ node }, vnode); + insertBefore(domParent, node, beforeEl); + break; + } + case map_kind: { + const head = this.#createHead("lustre:map", metaParent, index4, vnode); + insertBefore(domParent, head, beforeEl); + this.#insertChild(domParent, beforeEl, head[meta], 0, vnode.child); + break; + } + case memo_kind: { + const child2 = this.#memos?.get(vnode.view) ?? vnode.view(); + this.#insertChild(domParent, beforeEl, metaParent, index4, child2); + break; + } + } + } + #createElement(parent, index4, { kind, key, tag, namespace, attributes }) { + const node = createElementNS(namespace || NAMESPACE_HTML, tag); + insertMetadataChild(kind, parent, node, index4, key); + if (this.#debug && key) { + setAttribute(node, "data-lustre-key", key); + } + iterate(attributes, (attribute3) => this.#createAttribute(node, attribute3)); + return node; + } + #createTextNode(parent, index4, { kind, key, content }) { + const node = createTextNode(content ?? ""); + insertMetadataChild(kind, parent, node, index4, key); + return node; + } + #createHead(marker, parent, index4, { kind, key }) { + const node = this.#debug ? createComment(markerComment(marker, key)) : createTextNode(""); + insertMetadataChild(kind, parent, node, index4, key); + return node; + } + #createAttribute(node, attribute3) { + const { debouncers, handlers, throttles } = node[meta]; + const { + kind, + name: name2, + value: value2, + prevent_default: prevent, + debounce: debounceDelay, + throttle: throttleDelay + } = attribute3; + switch (kind) { + case attribute_kind: { + const valueOrDefault = value2 ?? ""; + if (name2 === "virtual:defaultValue") { + node.defaultValue = valueOrDefault; + return; + } else if (name2 === "virtual:defaultChecked") { + node.defaultChecked = true; + return; + } else if (name2 === "virtual:defaultSelected") { + node.defaultSelected = true; + return; + } + if (valueOrDefault !== getAttribute(node, name2)) { + setAttribute(node, name2, valueOrDefault); + } + SYNCED_ATTRIBUTES[name2]?.added?.(node, valueOrDefault); + break; + } + case property_kind: + node[name2] = value2; + break; + case event_kind: { + if (handlers.has(name2)) { + removeEventListener(node, name2, handleEvent); + } + const passive = prevent.kind === never_kind; + addEventListener(node, name2, handleEvent, { passive }); + this.#updateDebounceThrottle(throttles, name2, throttleDelay); + this.#updateDebounceThrottle(debouncers, name2, debounceDelay); + handlers.set(name2, (event3) => this.#handleEvent(attribute3, event3)); + break; + } + } + } + #updateDebounceThrottle(map7, name2, delay) { + const debounceOrThrottle = map7.get(name2); + if (delay > 0) { + if (debounceOrThrottle) { + debounceOrThrottle.delay = delay; + } else { + map7.set(name2, { delay }); + } + } else if (debounceOrThrottle) { + const { timeout } = debounceOrThrottle; + if (timeout) { + clearTimeout(timeout); + } + map7.delete(name2); + } + } + #handleEvent(attribute3, event3) { + const { currentTarget, type } = event3; + const { debouncers, throttles } = currentTarget[meta]; + const path = getPath(currentTarget); + const { + prevent_default: prevent, + stop_propagation: stop, + include + } = attribute3; + if (prevent.kind === always_kind) + event3.preventDefault(); + if (stop.kind === always_kind) + event3.stopPropagation(); + if (type === "submit") { + event3.detail ??= {}; + event3.detail.formData = [ + ...new FormData(event3.target, event3.submitter).entries() + ]; + } + const data = this.#decodeEvent(event3, path, type, include); + const throttle = throttles.get(type); + if (throttle) { + const now = Date.now(); + const last = throttle.last || 0; + if (now > last + throttle.delay) { + throttle.last = now; + throttle.lastEvent = event3; + this.#dispatch(event3, data); + } + } + const debounce = debouncers.get(type); + if (debounce) { + clearTimeout(debounce.timeout); + debounce.timeout = setTimeout(() => { + if (event3 === throttles.get(type)?.lastEvent) + return; + this.#dispatch(event3, data); + }, debounce.delay); + } + if (!throttle && !debounce) { + this.#dispatch(event3, data); + } + } +} +var markerComment = (marker, key) => { + if (key) { + return ` ${marker} key="${escape(key)}" `; + } else { + return ` ${marker} `; + } +}; +var handleEvent = (event3) => { + const { currentTarget, type } = event3; + const handler = currentTarget[meta].handlers.get(type); + handler(event3); +}; +var syncedBooleanAttribute = (name2) => { + return { + added(node) { + node[name2] = true; + }, + removed(node) { + node[name2] = false; + } + }; +}; +var syncedAttribute = (name2) => { + return { + added(node, value2) { + node[name2] = value2; + } + }; +}; +var SYNCED_ATTRIBUTES = { + checked: syncedBooleanAttribute("checked"), + selected: syncedBooleanAttribute("selected"), + value: syncedAttribute("value"), + autofocus: { + added(node) { + queueMicrotask(() => { + node.focus?.(); + }); + } + }, + autoplay: { + added(node) { + try { + node.play?.(); + } catch (e) { + console.error(e); + } + } + } +}; + +// build/dev/javascript/lustre/lustre/element/keyed.mjs +function do_extract_keyed_children(loop$key_children_pairs, loop$keyed_children, loop$children) { + while (true) { + let key_children_pairs = loop$key_children_pairs; + let keyed_children = loop$keyed_children; + let children = loop$children; + if (key_children_pairs instanceof Empty) { + return [keyed_children, reverse(children)]; + } else { + let rest = key_children_pairs.tail; + let key = key_children_pairs.head[0]; + let element$1 = key_children_pairs.head[1]; + let keyed_element = to_keyed(key, element$1); + let _block; + if (key === "") { + _block = keyed_children; + } else { + _block = insert2(keyed_children, key, keyed_element); + } + let keyed_children$1 = _block; + let children$1 = prepend(keyed_element, children); + loop$key_children_pairs = rest; + loop$keyed_children = keyed_children$1; + loop$children = children$1; + } + } +} +function extract_keyed_children(children) { + return do_extract_keyed_children(children, empty2(), empty_list); +} +function element3(tag, attributes, children) { + let $ = extract_keyed_children(children); + let keyed_children = $[0]; + let children$1 = $[1]; + return element("", "", tag, attributes, children$1, keyed_children, false, is_void_html_element(tag, "")); +} +function namespaced2(namespace, tag, attributes, children) { + let $ = extract_keyed_children(children); + let keyed_children = $[0]; + let children$1 = $[1]; + return element("", namespace, tag, attributes, children$1, keyed_children, false, is_void_html_element(tag, namespace)); +} +function fragment2(children) { + let $ = extract_keyed_children(children); + let keyed_children = $[0]; + let children$1 = $[1]; + return fragment("", children$1, keyed_children); +} + +// build/dev/javascript/lustre/lustre/vdom/virtualise.ffi.mjs +var virtualise = (root2) => { + const rootMeta = insertMetadataChild(element_kind, null, root2, 0, null); + const { children } = virtualiseChildren(rootMeta, root2, root2.firstChild); + if (children.length > 1) { + const rootNodeMeta = insertMetadataChild(element_kind, null, root2, 0, null); + rootMeta.kind = fragment_kind; + rootMeta.node = globalThis.document.createTextNode(""); + rootMeta.parent = rootNodeMeta; + rootNodeMeta.children.push(rootMeta); + root2.insertBefore(rootMeta.node, root2.firstChild); + return fragment2(toList3(children)); + } + if (children.length === 1) { + return children[0][1]; + } + const placeholder2 = globalThis.document.createTextNode(""); + insertMetadataChild(text_kind, rootMeta, placeholder2, 0, null); + root2.insertBefore(placeholder2, root2.firstChild); + return none2(); +}; +var virtualiseChild = (meta2, domParent, child2, index4) => { + if (child2.nodeType === COMMENT_NODE) { + const data = child2.data.trim(); + if (data.startsWith("lustre:fragment")) { + return virtualiseFragment(meta2, domParent, child2, index4); + } + if (data.startsWith("lustre:map")) { + return virtualiseMap(meta2, domParent, child2, index4); + } + if (data.startsWith("lustre:memo")) { + return virtualiseMemo(meta2, domParent, child2, index4); + } + return null; + } + if (child2.nodeType === ELEMENT_NODE) { + return virtualiseElement(meta2, child2, index4); + } + if (child2.nodeType === TEXT_NODE) { + return virtualiseText(meta2, child2, index4); + } + return null; +}; +var virtualiseElement = (metaParent, node, index4) => { + const key = node.getAttribute("data-lustre-key") ?? ""; + if (key) { + node.removeAttribute("data-lustre-key"); + } + const meta2 = insertMetadataChild(element_kind, metaParent, node, index4, key); + const tag = node.localName; + const namespace = node.namespaceURI; + const isHtmlElement = !namespace || namespace === NAMESPACE_HTML; + if (isHtmlElement && INPUT_ELEMENTS.includes(tag)) { + virtualiseInputEvents(tag, node); + } + const attributes = virtualiseAttributes(node); + const { children } = virtualiseChildren(meta2, node, node.firstChild); + const vnode = isHtmlElement ? element3(tag, attributes, toList3(children)) : namespaced2(namespace, tag, attributes, toList3(children)); + return childResult(key, vnode, node.nextSibling); +}; +var virtualiseChildren = (meta2, domParent, childNode) => { + const children = []; + while (childNode && (childNode.nodeType !== COMMENT_NODE || childNode.data.trim() !== "/lustre:fragment")) { + const child2 = virtualiseChild(meta2, domParent, childNode, children.length); + if (child2) { + children.push([child2.key, child2.vnode]); + childNode = child2.next; + } else { + childNode = childNode.nextSibling; + } + } + return { children, end: childNode }; +}; +var virtualiseText = (meta2, node, index4) => { + insertMetadataChild(text_kind, meta2, node, index4, null); + return childResult("", text2(node.data), node.nextSibling); +}; +var virtualiseFragment = (metaParent, domParent, node, index4) => { + const key = parseKey(node.data); + const meta2 = insertMetadataChild(fragment_kind, metaParent, node, index4, key); + const { children, end } = virtualiseChildren(meta2, domParent, node.nextSibling); + meta2.endNode = end; + const vnode = fragment2(toList3(children)); + return childResult(key, vnode, end?.nextSibling); +}; +var virtualiseMap = (metaParent, domParent, node, index4) => { + const key = parseKey(node.data); + const meta2 = insertMetadataChild(map_kind, metaParent, node, index4, key); + const child2 = virtualiseNextChild(meta2, domParent, node, 0); + if (!child2) + return null; + const vnode = map6(child2.vnode, (x) => x); + return childResult(key, vnode, child2.next); +}; +var virtualiseMemo = (meta2, domParent, node, index4) => { + const key = parseKey(node.data); + const child2 = virtualiseNextChild(meta2, domParent, node, index4); + if (!child2) + return null; + domParent.removeChild(node); + const vnode = memo2(toList3([ref({})]), () => child2.vnode); + return childResult(key, vnode, child2.next); +}; +var virtualiseNextChild = (meta2, domParent, node, index4) => { + while (true) { + node = node.nextSibling; + if (!node) + return null; + const child2 = virtualiseChild(meta2, domParent, node, index4); + if (child2) + return child2; + } +}; +var childResult = (key, vnode, next) => { + return { key, vnode, next }; +}; +var virtualiseAttributes = (node) => { + const attributes = []; + for (let i = 0;i < node.attributes.length; i++) { + const attr = node.attributes[i]; + if (attr.name !== "xmlns") { + attributes.push(attribute2(attr.localName, attr.value)); + } + } + return toList3(attributes); +}; +var INPUT_ELEMENTS = ["input", "select", "textarea"]; +var virtualiseInputEvents = (tag, node) => { + const value2 = node.value; + const checked = node.checked; + if (tag === "input" && node.type === "checkbox" && !checked) + return; + if (tag === "input" && node.type === "radio" && !checked) + return; + if (node.type !== "checkbox" && node.type !== "radio" && !value2) + return; + queueMicrotask(() => { + node.value = value2; + node.checked = checked; + node.dispatchEvent(new Event("input", { bubbles: true })); + node.dispatchEvent(new Event("change", { bubbles: true })); + if (globalThis.document.activeElement !== node) { + node.dispatchEvent(new Event("blur", { bubbles: true })); + } + }); +}; +var parseKey = (data) => { + const keyMatch = data.match(/key="([^"]*)"/); + if (!keyMatch) + return ""; + return unescapeKey(keyMatch[1]); +}; +var unescapeKey = (key) => { + return key.replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/&/g, "&").replace(/'/g, "'"); +}; +var toList3 = (arr) => arr.reduceRight((xs, x) => List$NonEmpty(x, xs), empty_list); + +// build/dev/javascript/lustre/lustre/runtime/client/runtime.ffi.mjs +var is_browser = () => !!globalThis.document; +class Runtime { + constructor(root2, [model, effects], view, update2, options) { + this.root = root2; + this.#model = model; + this.#view = view; + this.#update = update2; + this.root.addEventListener("context-request", (event3) => { + if (!(event3.context && event3.callback)) + return; + if (!this.#contexts.has(event3.context)) + return; + event3.stopImmediatePropagation(); + const context = this.#contexts.get(event3.context); + if (event3.subscribe) { + const unsubscribe2 = () => { + context.subscribers = context.subscribers.filter((subscriber) => subscriber !== event3.callback); + }; + context.subscribers.push([event3.callback, unsubscribe2]); + event3.callback(context.value, unsubscribe2); + } else { + event3.callback(context.value); + } + }); + const decodeEvent = (event3, path, name2) => decode2(this.#cache, path, name2, event3); + const dispatch2 = (event3, data) => { + const [cache, result] = dispatch(this.#cache, data); + this.#cache = cache; + if (Result$isOk(result)) { + const handler = Result$Ok$0(result); + if (handler.stop_propagation) + event3.stopPropagation(); + if (handler.prevent_default) + event3.preventDefault(); + this.dispatch(handler.message, false); + } + }; + this.#reconciler = new Reconciler(this.root, decodeEvent, dispatch2, options); + this.#vdom = virtualise(this.root); + this.#cache = new$4(); + this.#handleEffects(effects); + this.#render(); + } + root = null; + dispatch(message, shouldFlush = false) { + if (this.#shouldQueue) { + this.#queue.push(message); + } else { + const [model, effects] = this.#update(this.#model, message); + this.#model = model; + this.#scheduleRender(shouldFlush); + this.#handleEffects(effects); + } + } + emit(event3, data) { + const target = this.root.host ?? this.root; + target.dispatchEvent(new LustreEvent(event3, data)); + } + provide(key, value2) { + if (!this.#contexts.has(key)) { + this.#contexts.set(key, { value: value2, subscribers: [] }); + } else { + const context = this.#contexts.get(key); + if (isEqual2(context.value, value2)) { + return; + } + context.value = value2; + for (let i = context.subscribers.length - 1;i >= 0; i--) { + const [subscriber, unsubscribe2] = context.subscribers[i]; + if (!subscriber) { + context.subscribers.splice(i, 1); + continue; + } + subscriber(value2, unsubscribe2); + } + } + } + subscribe(key, decoder) { + if (!key) + return; + this.#contextSubscriptions.get(key)?.(); + const target = this.root.host ?? this.root; + target.dispatchEvent(new ContextRequestEvent(key, (value2, unsubscribe2) => { + const previousUnsubscribe = this.#contextSubscriptions.get(key); + if (previousUnsubscribe !== unsubscribe2) { + previousUnsubscribe?.(); + } + const decoded = run(value2, decoder); + this.#contextSubscriptions.set(key, unsubscribe2); + if (Result$isOk(decoded)) { + this.dispatch(Result$Ok$0(decoded), true); + } + }, true)); + } + unsubscribe(key) { + const unsubscribe2 = this.#contextSubscriptions.get(key); + if (unsubscribe2) { + unsubscribe2(); + this.#contextSubscriptions.delete(key); + } + } + unsubscribeAll() { + for (const [_, unsubscribe2] of this.#contextSubscriptions) { + unsubscribe2?.(); + } + this.#contextSubscriptions.clear(); + } + #model; + #view; + #update; + #vdom; + #cache; + #reconciler; + #contexts = new Map; + #contextSubscriptions = new Map; + #shouldQueue = false; + #queue = []; + #beforePaint = empty_list; + #afterPaint = empty_list; + #renderTimer = null; + #actions = { + dispatch: (message) => this.dispatch(message), + emit: (event3, data) => this.emit(event3, data), + select: () => {}, + root: () => this.root, + provide: (key, value2) => this.provide(key, value2), + subscribe: (key, decoder) => this.subscribe(key, decoder), + unsubscribe: (key) => this.unsubscribe(key) + }; + #scheduleRender(shouldFlush = false) { + if (this.#renderTimer) + return; + if (shouldFlush) { + this.#renderTimer = "sync"; + queueMicrotask(() => this.#render()); + } else { + this.#renderTimer = window.requestAnimationFrame(() => this.#render()); + } + } + #handleEffects(effects) { + this.#shouldQueue = true; + let updateCalledDuringEffects = false; + while (true) { + iterate(effects.synchronous, (effect) => effect(this.#actions)); + this.#beforePaint = append4(this.#beforePaint, effects.before_paint); + this.#afterPaint = append4(this.#afterPaint, effects.after_paint); + if (!this.#queue.length) + break; + const message = this.#queue.shift(); + [this.#model, effects] = this.#update(this.#model, message); + updateCalledDuringEffects = true; + } + this.#shouldQueue = false; + return updateCalledDuringEffects; + } + #handleAsyncEffects(effects) { + if (this.#handleEffects(effects)) { + this.#scheduleRender(true); + } + } + #render() { + this.#renderTimer = null; + const next = this.#view(this.#model); + const { patch, cache } = diff(this.#cache, this.#vdom, next); + this.#cache = cache; + this.#vdom = next; + this.#reconciler.push(patch, memos(cache)); + if (List$isNonEmpty(this.#beforePaint)) { + const effects = makeEffect(this.#beforePaint); + this.#beforePaint = empty_list; + queueMicrotask(() => this.#handleAsyncEffects(effects)); + } + if (List$isNonEmpty(this.#afterPaint)) { + const effects = makeEffect(this.#afterPaint); + this.#afterPaint = empty_list; + window.requestAnimationFrame(() => this.#handleAsyncEffects(effects)); + } + } +} +function makeEffect(synchronous) { + return { + synchronous, + after_paint: empty_list, + before_paint: empty_list + }; +} +var copiedStyleSheets = new WeakMap; +class ContextRequestEvent extends Event { + constructor(context, callback, subscribe2) { + super("context-request", { bubbles: true, composed: true }); + this.context = context; + this.callback = callback; + this.subscribe = subscribe2; + } +} + +class LustreEvent extends CustomEvent { + isLustreEvent = true; + constructor(name2, detail) { + super(name2, { detail, bubbles: true, composed: true }); + } +} + +// build/dev/javascript/lustre/lustre/runtime/client/spa.ffi.mjs +class Spa { + #runtime; + constructor(root2, [init, effects], update2, view) { + this.#runtime = new Runtime(root2, [init, effects], view, update2); + } + send(message) { + if (Message$isEffectDispatchedMessage(message)) { + this.dispatch(message.message, false); + } else if (Message$isEffectEmitEvent(message)) { + this.emit(message.name, message.data); + } else if (Message$isSystemRequestedShutdown(message)) {} + } + dispatch(message) { + this.#runtime.dispatch(message); + } + emit(event3, data) { + this.#runtime.emit(event3, data); + } +} +var start = ({ init, update: update2, view }, selector, flags) => { + if (!is_browser()) + return Result$Error(Error$NotABrowser()); + const root2 = selector instanceof HTMLElement ? selector : globalThis.document.querySelector(selector); + if (!root2) + return Result$Error(Error$ElementNotFound(selector)); + return Result$Ok(new Spa(root2, init(flags), update2, view)); +}; + +// build/dev/javascript/lustre/lustre/runtime/server/runtime.ffi.mjs +class Runtime2 { + #model; + #update; + #view; + #config; + #vdom; + #cache; + #providers = make(); + #callbacks = /* @__PURE__ */ new Set; + constructor(_, init, update2, view, config, start_arguments) { + const [model, effects] = init(start_arguments); + this.#model = model; + this.#update = update2; + this.#view = view; + this.#config = config; + this.#vdom = this.#view(this.#model); + this.#cache = from_node(this.#vdom); + this.#handle_effect(effects); + } + send(message) { + if (Message$isClientDispatchedMessage(message)) { + const { message: message2 } = message2; + const next = this.#handle_client_message(message2); + const diff2 = diff(this.#cache, this.#vdom, next); + this.#vdom = next; + this.#cache = diff2.cache; + this.broadcast(reconcile(diff2.patch, memos(diff2.cache))); + } else if (Message$isClientRegisteredCallback(message)) { + const { callback } = message; + this.#callbacks.add(callback); + callback(mount(this.#config.open_shadow_root, this.#config.adopt_styles, keys(this.#config.attributes), keys(this.#config.properties), keys(this.#config.contexts), this.#providers, this.#vdom, memos(this.#cache))); + if (Option$isSome(this.#config.on_connect)) { + this.#dispatch(Option$Some$0(this.#config.on_connect)); + } + } else if (Message$isClientDeregisteredCallback(message)) { + const { callback } = message; + this.#callbacks.delete(callback); + if (Option$isSome(this.#config.on_disconnect)) { + this.#dispatch(Option$Some$0(this.#config.on_disconnect)); + } + } else if (Message$isEffectDispatchedMessage(message)) { + const { message: message2 } = message2; + const [model, effect] = this.#update(this.#model, message2); + const next = this.#view(model); + const diff2 = diff(this.#cache, this.#vdom, next); + this.#handle_effect(effect); + this.#model = model; + this.#vdom = next; + this.#cache = diff2.cache; + this.broadcast(reconcile(diff2.patch, memos(diff2.cache))); + } else if (Message$isEffectEmitEvent(message)) { + const { name: name2, data } = message; + this.broadcast(emit(name2, data)); + } else if (Message$isEffectProvidedValue(message)) { + const { key, value: value2 } = message; + const existing = get(this.#providers, key); + if (Result$isOk(existing) && isEqual2(Result$Ok$0(existing), value2)) { + return; + } + this.#providers = insert(this.#providers, key, value2); + this.broadcast(provide(key, value2)); + } else if (Message$isEffectRequestedContextSubscription(message)) { + const { key, decoder } = message; + this.broadcast(subscribe(key)); + this.#config.contexts = insert(this.#config.contexts, key, decoder); + } else if (Message$isEffectRemovedContextSubscription(message)) { + const { key } = message; + this.broadcast(unsubscribe(key)); + this.#config.contexts = delete$(this.#config.contexts, key); + } else if (Message$isSystemRequestedShutdown(message)) { + this.#model = null; + this.#update = null; + this.#view = null; + this.#config = null; + this.#vdom = null; + this.#cache = null; + this.#providers = null; + this.#callbacks.clear(); + } + } + broadcast(message) { + for (const callback of this.#callbacks) { + callback(message); + } + } + #handle_client_message(message) { + if (ServerMessage$isBatch(message)) { + const { messages } = message; + let model = this.#model; + let effect = none(); + for (let list4 = messages;List$NonEmpty$rest(list4); list4 = List$NonEmpty$rest(list4)) { + const result = this.#handle_client_message(List$NonEmpty$first(list4)); + if (Result$isOk(result)) { + model = Result$Ok$0(result)[0]; + effect = batch(toList2([effect, Result$Ok$0(result)[1]])); + break; + } + } + this.#handle_effect(effect); + this.#model = model; + return this.#view(model); + } else if (ServerMessage$isAttributeChanged(message)) { + const { name: name2, value: value2 } = message; + const result = this.#handle_attribute_change(name2, value2); + if (!Result$isOk(result)) { + return this.#vdom; + } + return this.#dispatch(Result$Ok$0(result)); + } else if (ServerMessage$isPropertyChanged(message)) { + const { name: name2, value: value2 } = message; + const result = this.#handle_properties_change(name2, value2); + if (!Result$isOk(result)) { + return this.#vdom; + } + return this.#dispatch(Result$Ok$0(result)); + } else if (ServerMessage$isEventFired(message)) { + const { path, name: name2, event: event3 } = message2; + const [cache, result] = handle(this.#cache, path, name2, event3); + this.#cache = cache; + if (!Result$isOk(result)) { + return this.#vdom; + } + const { message: message2 } = Result$Ok$0(result); + return this.#dispatch(message2); + } else if (ServerMessage$isContextProvided(message)) { + const { key, value: value2 } = message; + let result = get(this.#config.contexts, key); + if (!Result$isOk(result)) { + return this.#vdom; + } + result = run(value2, Result$Ok$0(result)); + if (!Result$isOk(result)) { + return this.#vdom; + } + return this.#dispatch(Result$Ok$0(result)); + } + } + #dispatch(message) { + const [model, effects] = this.#update(this.#model, message); + this.#handle_effect(effects); + this.#model = model; + return this.#view(this.#model); + } + #handle_attribute_change(name2, value2) { + const result = get(this.#config.attributes, name2); + if (!Result$isOk(result)) { + return result; + } + return Result$Ok$0(result)(value2); + } + #handle_properties_change(name2, value2) { + const result = get(this.#config.properties, name2); + if (!Result$isOk(result)) { + return result; + } + return Result$Ok$0(result)(value2); + } + #handle_effect(effect) { + const dispatch2 = (message) => this.send(Message$EffectDispatchedMessage(message)); + const emit2 = (name2, data) => this.send(Message$EffectEmitEvent(name2, data)); + const select = () => { + return; + }; + const internals = () => { + return; + }; + const provide2 = (key, value2) => this.send(Message$EffectProvidedValue(key, value2)); + const subscribe2 = (key, decoder) => this.send(Message$EffectRequestedContextSubscription(key, decoder)); + const unsubscribe2 = (key) => this.send(Message$EffectRemovedContextSubscription(key)); + globalThis.queueMicrotask(() => { + perform(effect, dispatch2, emit2, select, internals, provide2, subscribe2, unsubscribe2); + }); + } +} + +// build/dev/javascript/lustre/lustre.mjs +class ElementNotFound extends CustomType { + constructor(selector) { + super(); + this.selector = selector; + } +} +var Error$ElementNotFound = (selector) => new ElementNotFound(selector); +class NotABrowser extends CustomType { +} +var Error$NotABrowser$const = new NotABrowser; +var Error$NotABrowser = () => Error$NotABrowser$const; +function application(init, update2, view) { + return new App(Option$None$const, init, update2, view, default_config); +} +function start4(app, selector, arguments$) { + return guard(!is_browser(), new Error2(Error$NotABrowser$const), () => { + return start(app, selector, arguments$); + }); +} + +// build/dev/javascript/gleam_stdlib/gleam/pair.mjs +function new$5(first, second) { + return [first, second]; +} + +// build/dev/javascript/lustre/lustre/event.mjs +function on(name2, handler) { + return event(name2, map3(handler, (message) => { + return new Handler(false, false, message); + }), empty_list, never, never, 0, 0); +} +function prevent_default(event4) { + if (event4 instanceof Event2) { + return new Event2(event4.kind, event4.name, event4.handler, event4.include, always, event4.stop_propagation, event4.debounce, event4.throttle); + } else { + return event4; + } +} +function on_click(message) { + return on("click", success(message)); +} +function on_input(message) { + return on("input", subfield(toList(["target", "value"]), string3, (value2) => { + return success(message(value2)); + })); +} +function formdata_decoder() { + let string_value_decoder = field(0, string3, (key) => { + return field(1, one_of(map3(string3, (var0) => { + return new Ok(var0); + }), toList([success(error_nil)])), (value2) => { + let _pipe2 = value2; + let _pipe$12 = map4(_pipe2, (_capture) => { + return new$5(key, _capture); + }); + return success(_pipe$12); + }); + }); + let _pipe = string_value_decoder; + let _pipe$1 = list2(_pipe); + return map3(_pipe$1, values2); +} +function on_submit(message) { + let _pipe = on("submit", subfield(toList(["detail", "formData"]), formdata_decoder(), (formdata) => { + let _pipe2 = formdata; + let _pipe$1 = message(_pipe2); + return success(_pipe$1); + })); + return prevent_default(_pipe); +} +// build/dev/javascript/plinth/location_ffi.mjs +function pathname(location) { + return location.pathname; +} +// build/dev/javascript/gleam_javascript/gleam_javascript_ffi.mjs +class PromiseLayer { + constructor(promise) { + this.promise = promise; + } + static wrap(value2) { + return value2 instanceof Promise ? new PromiseLayer(value2) : value2; + } + static unwrap(value2) { + return value2 instanceof PromiseLayer ? value2.promise : value2; + } +} +function resolve(value2) { + return Promise.resolve(PromiseLayer.wrap(value2)); +} +function then_await(promise, fn) { + return promise.then((value2) => fn(PromiseLayer.unwrap(value2))); +} +function map_promise(promise, fn) { + return promise.then((value2) => PromiseLayer.wrap(fn(PromiseLayer.unwrap(value2)))); +} +function rescue(promise, fn) { + return promise.catch((error) => fn(error)); +} + +// build/dev/javascript/gleam_javascript/gleam/javascript/promise.mjs +function tap(promise, callback) { + let _pipe = promise; + return map_promise(_pipe, (a2) => { + callback(a2); + return a2; + }); +} +function try_await(promise, callback) { + let _pipe = promise; + return then_await(_pipe, (result) => { + if (result instanceof Ok) { + let a2 = result[0]; + return callback(a2); + } else { + let e = result[0]; + return resolve(new Error2(e)); + } + }); +} + +// build/dev/javascript/plinth/plinth/browser/element.mjs +class BeforeBegin extends CustomType { +} +var Position$BeforeBegin$const = new BeforeBegin; +class AfterBegin extends CustomType { +} +var Position$AfterBegin$const = new AfterBegin; +class BeforeEnd extends CustomType { +} +var Position$BeforeEnd$const = new BeforeEnd; +class AfterEnd extends CustomType { +} +var Position$AfterEnd$const = new AfterEnd; + +// build/dev/javascript/plinth/window_ffi.mjs +function crypto(self) { + const crypto2 = self.crypto; + if (crypto2 && crypto2 instanceof globalThis.Crypto) { + return Result$Ok(crypto2); + } + return Result$Error(); +} +function self() { + return globalThis; +} +function alert(message) { + window.alert(message); +} +function confirm(message) { + return window.confirm(message); +} +function prompt(message, defaultValue) { + let text4 = window.prompt(message, defaultValue); + if (text4 !== null) { + return Result$Ok(text4); + } else { + return Result$Error(); + } +} +function addEventListener4(type, listener) { + return window.addEventListener(type, listener); +} +function document2(window2) { + return window2.document; +} +async function requestWakeLock() { + try { + return Result$Ok(await window.navigator.wakeLock.request("screen")); + } catch (error) { + return Result$Error(error.toString()); + } +} +function location(window2) { + return window2.location; +} +function focus2(w) { + return w.focus(); +} +function innerHeight(w) { + return w.innerHeight; +} +function innerWidth(w) { + return w.innerWidth; +} +function outerHeight(w) { + return w.outerHeight; +} +function outerWidth(w) { + return w.outerWidth; +} +function screenX(w) { + return w.screenX; +} +function screenY(w) { + return w.screenY; +} +function screenTop(w) { + return w.screenTop; +} +function screenLeft(w) { + return w.screenLeft; +} +function scrollX(w) { + return w.scrollX; +} +function scrollY(w) { + return w.scrollY; +} +function opener(window2) { + const opener2 = window2.opener; + if (opener2) { + return Result$Ok(opener2); + } else { + return Result$Error(); + } +} +function postMessage(window2, message, targetOrigin) { + window2.postMessage(message, targetOrigin); +} +function onMessage(worker2, callback) { + worker2.addEventListener("message", function(message) { + callback(message); + }); +} +function open(url, target2, features) { + try { + return Result$Ok(window.open(url, target2, features)); + } catch (error) { + return Result$Error(error.toString()); + } +} +function close(w) { + w.close(); +} +function closed(w) { + return w.closed; +} +function queueMicrotask2(callback) { + return window.queueMicrotask(callback); +} +function requestAnimationFrame(callback) { + return window.requestAnimationFrame(callback); +} +function cancelAnimationFrame(callback) { + return window.cancelAnimationFrame(callback); +} +function eval_(string) { + try { + return Result$Ok(eval(string)); + } catch (error) { + return Result$Error(error.toString()); + } +} +async function import_(string6) { + try { + return Result$Ok(await import(string6)); + } catch (error) { + return Result$Error(error.toString()); + } +} + +// build/dev/javascript/gleam_stdlib/gleam/uri.mjs +class Uri extends CustomType { + constructor(scheme, userinfo, host, port, path, query, fragment3) { + super(); + this.scheme = scheme; + this.userinfo = userinfo; + this.host = host; + this.port = port; + this.path = path; + this.query = query; + this.fragment = fragment3; + } +} +var empty3 = /* @__PURE__ */ new Uri(Option$None$const, Option$None$const, Option$None$const, Option$None$const, "", Option$None$const, Option$None$const); +function parse_fragment(rest, pieces) { + return new Ok(new Uri(pieces.scheme, pieces.userinfo, pieces.host, pieces.port, pieces.path, pieces.query, new Some(rest))); +} +function parse_query_with_question_mark_loop(loop$original, loop$uri_string, loop$pieces, loop$size) { + while (true) { + let original = loop$original; + let uri_string = loop$uri_string; + let pieces = loop$pieces; + let size3 = loop$size; + if (uri_string.charCodeAt(0) === 35) { + if (size3 === 0) { + let rest = uri_string.slice(1); + return parse_fragment(rest, pieces); + } else { + let rest = uri_string.slice(1); + let query = string_codeunit_slice(original, 0, size3); + let pieces$1 = new Uri(pieces.scheme, pieces.userinfo, pieces.host, pieces.port, pieces.path, new Some(query), pieces.fragment); + return parse_fragment(rest, pieces$1); + } + } else if (uri_string === "") { + return new Ok(new Uri(pieces.scheme, pieces.userinfo, pieces.host, pieces.port, pieces.path, new Some(original), pieces.fragment)); + } else { + let $ = pop_codeunit(uri_string); + let rest = $[1]; + loop$original = original; + loop$uri_string = rest; + loop$pieces = pieces; + loop$size = size3 + 1; + } + } +} +function parse_query_with_question_mark(uri_string, pieces) { + return parse_query_with_question_mark_loop(uri_string, uri_string, pieces, 0); +} +function parse_path_loop(loop$original, loop$uri_string, loop$pieces, loop$size) { + while (true) { + let original = loop$original; + let uri_string = loop$uri_string; + let pieces = loop$pieces; + let size3 = loop$size; + let $ = uri_string.charCodeAt(0); + if ($ === 63) { + let rest = uri_string.slice(1); + let path = string_codeunit_slice(original, 0, size3); + let pieces$1 = new Uri(pieces.scheme, pieces.userinfo, pieces.host, pieces.port, path, pieces.query, pieces.fragment); + return parse_query_with_question_mark(rest, pieces$1); + } else if ($ === 35) { + let rest = uri_string.slice(1); + let path = string_codeunit_slice(original, 0, size3); + let pieces$1 = new Uri(pieces.scheme, pieces.userinfo, pieces.host, pieces.port, path, pieces.query, pieces.fragment); + return parse_fragment(rest, pieces$1); + } else if (uri_string === "") { + return new Ok(new Uri(pieces.scheme, pieces.userinfo, pieces.host, pieces.port, original, pieces.query, pieces.fragment)); + } else { + let $1 = pop_codeunit(uri_string); + let rest = $1[1]; + loop$original = original; + loop$uri_string = rest; + loop$pieces = pieces; + loop$size = size3 + 1; + } + } +} +function parse_path(uri_string, pieces) { + return parse_path_loop(uri_string, uri_string, pieces, 0); +} +function parse_port_loop(loop$uri_string, loop$pieces, loop$port) { + while (true) { + let uri_string = loop$uri_string; + let pieces = loop$pieces; + let port = loop$port; + let $ = uri_string.charCodeAt(0); + if ($ === 48) { + let rest = uri_string.slice(1); + loop$uri_string = rest; + loop$pieces = pieces; + loop$port = port * 10; + } else if ($ === 49) { + let rest = uri_string.slice(1); + loop$uri_string = rest; + loop$pieces = pieces; + loop$port = port * 10 + 1; + } else if ($ === 50) { + let rest = uri_string.slice(1); + loop$uri_string = rest; + loop$pieces = pieces; + loop$port = port * 10 + 2; + } else if ($ === 51) { + let rest = uri_string.slice(1); + loop$uri_string = rest; + loop$pieces = pieces; + loop$port = port * 10 + 3; + } else if ($ === 52) { + let rest = uri_string.slice(1); + loop$uri_string = rest; + loop$pieces = pieces; + loop$port = port * 10 + 4; + } else if ($ === 53) { + let rest = uri_string.slice(1); + loop$uri_string = rest; + loop$pieces = pieces; + loop$port = port * 10 + 5; + } else if ($ === 54) { + let rest = uri_string.slice(1); + loop$uri_string = rest; + loop$pieces = pieces; + loop$port = port * 10 + 6; + } else if ($ === 55) { + let rest = uri_string.slice(1); + loop$uri_string = rest; + loop$pieces = pieces; + loop$port = port * 10 + 7; + } else if ($ === 56) { + let rest = uri_string.slice(1); + loop$uri_string = rest; + loop$pieces = pieces; + loop$port = port * 10 + 8; + } else if ($ === 57) { + let rest = uri_string.slice(1); + loop$uri_string = rest; + loop$pieces = pieces; + loop$port = port * 10 + 9; + } else if ($ === 63) { + let rest = uri_string.slice(1); + let pieces$1 = new Uri(pieces.scheme, pieces.userinfo, pieces.host, new Some(port), pieces.path, pieces.query, pieces.fragment); + return parse_query_with_question_mark(rest, pieces$1); + } else if ($ === 35) { + let rest = uri_string.slice(1); + let pieces$1 = new Uri(pieces.scheme, pieces.userinfo, pieces.host, new Some(port), pieces.path, pieces.query, pieces.fragment); + return parse_fragment(rest, pieces$1); + } else if ($ === 47) { + let pieces$1 = new Uri(pieces.scheme, pieces.userinfo, pieces.host, new Some(port), pieces.path, pieces.query, pieces.fragment); + return parse_path(uri_string, pieces$1); + } else if (uri_string === "") { + return new Ok(new Uri(pieces.scheme, pieces.userinfo, pieces.host, new Some(port), pieces.path, pieces.query, pieces.fragment)); + } else { + return new Error2(undefined); + } + } +} +function parse_port(uri_string, pieces) { + let $ = uri_string.charCodeAt(0); + if (uri_string.startsWith(":0")) { + let rest = uri_string.slice(2); + return parse_port_loop(rest, pieces, 0); + } else if (uri_string.startsWith(":1")) { + let rest = uri_string.slice(2); + return parse_port_loop(rest, pieces, 1); + } else if (uri_string.startsWith(":2")) { + let rest = uri_string.slice(2); + return parse_port_loop(rest, pieces, 2); + } else if (uri_string.startsWith(":3")) { + let rest = uri_string.slice(2); + return parse_port_loop(rest, pieces, 3); + } else if (uri_string.startsWith(":4")) { + let rest = uri_string.slice(2); + return parse_port_loop(rest, pieces, 4); + } else if (uri_string.startsWith(":5")) { + let rest = uri_string.slice(2); + return parse_port_loop(rest, pieces, 5); + } else if (uri_string.startsWith(":6")) { + let rest = uri_string.slice(2); + return parse_port_loop(rest, pieces, 6); + } else if (uri_string.startsWith(":7")) { + let rest = uri_string.slice(2); + return parse_port_loop(rest, pieces, 7); + } else if (uri_string.startsWith(":8")) { + let rest = uri_string.slice(2); + return parse_port_loop(rest, pieces, 8); + } else if (uri_string.startsWith(":9")) { + let rest = uri_string.slice(2); + return parse_port_loop(rest, pieces, 9); + } else if (uri_string === ":") { + return new Ok(pieces); + } else if (uri_string === "") { + return new Ok(pieces); + } else if ($ === 63) { + let rest = uri_string.slice(1); + return parse_query_with_question_mark(rest, pieces); + } else if (uri_string.startsWith(":?")) { + let rest = uri_string.slice(2); + return parse_query_with_question_mark(rest, pieces); + } else if ($ === 35) { + let rest = uri_string.slice(1); + return parse_fragment(rest, pieces); + } else if (uri_string.startsWith(":#")) { + let rest = uri_string.slice(2); + return parse_fragment(rest, pieces); + } else if ($ === 47) { + return parse_path(uri_string, pieces); + } else if ($ === 58) { + let rest = uri_string.slice(1); + if (rest.charCodeAt(0) === 47) { + return parse_path(rest, pieces); + } else { + return new Error2(undefined); + } + } else { + return new Error2(undefined); + } +} +function parse_host_outside_of_brackets_loop(loop$original, loop$uri_string, loop$pieces, loop$size) { + while (true) { + let original = loop$original; + let uri_string = loop$uri_string; + let pieces = loop$pieces; + let size3 = loop$size; + let $ = uri_string.charCodeAt(0); + if (uri_string === "") { + return new Ok(new Uri(pieces.scheme, pieces.userinfo, new Some(original), pieces.port, pieces.path, pieces.query, pieces.fragment)); + } else if ($ === 58) { + let host = string_codeunit_slice(original, 0, size3); + let pieces$1 = new Uri(pieces.scheme, pieces.userinfo, new Some(host), pieces.port, pieces.path, pieces.query, pieces.fragment); + return parse_port(uri_string, pieces$1); + } else if ($ === 47) { + let host = string_codeunit_slice(original, 0, size3); + let pieces$1 = new Uri(pieces.scheme, pieces.userinfo, new Some(host), pieces.port, pieces.path, pieces.query, pieces.fragment); + return parse_path(uri_string, pieces$1); + } else if ($ === 63) { + let rest = uri_string.slice(1); + let host = string_codeunit_slice(original, 0, size3); + let pieces$1 = new Uri(pieces.scheme, pieces.userinfo, new Some(host), pieces.port, pieces.path, pieces.query, pieces.fragment); + return parse_query_with_question_mark(rest, pieces$1); + } else if ($ === 35) { + let rest = uri_string.slice(1); + let host = string_codeunit_slice(original, 0, size3); + let pieces$1 = new Uri(pieces.scheme, pieces.userinfo, new Some(host), pieces.port, pieces.path, pieces.query, pieces.fragment); + return parse_fragment(rest, pieces$1); + } else { + let $1 = pop_codeunit(uri_string); + let rest = $1[1]; + loop$original = original; + loop$uri_string = rest; + loop$pieces = pieces; + loop$size = size3 + 1; + } + } +} +function parse_host_outside_of_brackets(uri_string, pieces) { + return parse_host_outside_of_brackets_loop(uri_string, uri_string, pieces, 0); +} +function is_valid_host_within_brackets_char(char) { + return 48 >= char && char <= 57 || 65 >= char && char <= 90 || 97 >= char && char <= 122 || char === 58 || char === 46; +} +function parse_host_within_brackets_loop(loop$original, loop$uri_string, loop$pieces, loop$size) { + while (true) { + let original = loop$original; + let uri_string = loop$uri_string; + let pieces = loop$pieces; + let size3 = loop$size; + let $ = uri_string.charCodeAt(0); + if (uri_string === "") { + return new Ok(new Uri(pieces.scheme, pieces.userinfo, new Some(uri_string), pieces.port, pieces.path, pieces.query, pieces.fragment)); + } else if ($ === 93) { + if (size3 === 0) { + let rest = uri_string.slice(1); + return parse_port(rest, pieces); + } else { + let rest = uri_string.slice(1); + let host = string_codeunit_slice(original, 0, size3 + 1); + let pieces$1 = new Uri(pieces.scheme, pieces.userinfo, new Some(host), pieces.port, pieces.path, pieces.query, pieces.fragment); + return parse_port(rest, pieces$1); + } + } else if ($ === 47) { + if (size3 === 0) { + return parse_path(uri_string, pieces); + } else { + let host = string_codeunit_slice(original, 0, size3); + let pieces$1 = new Uri(pieces.scheme, pieces.userinfo, new Some(host), pieces.port, pieces.path, pieces.query, pieces.fragment); + return parse_path(uri_string, pieces$1); + } + } else if ($ === 63) { + if (size3 === 0) { + let rest = uri_string.slice(1); + return parse_query_with_question_mark(rest, pieces); + } else { + let rest = uri_string.slice(1); + let host = string_codeunit_slice(original, 0, size3); + let pieces$1 = new Uri(pieces.scheme, pieces.userinfo, new Some(host), pieces.port, pieces.path, pieces.query, pieces.fragment); + return parse_query_with_question_mark(rest, pieces$1); + } + } else if ($ === 35) { + if (size3 === 0) { + let rest = uri_string.slice(1); + return parse_fragment(rest, pieces); + } else { + let rest = uri_string.slice(1); + let host = string_codeunit_slice(original, 0, size3); + let pieces$1 = new Uri(pieces.scheme, pieces.userinfo, new Some(host), pieces.port, pieces.path, pieces.query, pieces.fragment); + return parse_fragment(rest, pieces$1); + } + } else { + let $1 = pop_codeunit(uri_string); + let char = $1[0]; + let rest = $1[1]; + let $2 = is_valid_host_within_brackets_char(char); + if ($2) { + loop$original = original; + loop$uri_string = rest; + loop$pieces = pieces; + loop$size = size3 + 1; + } else { + return parse_host_outside_of_brackets_loop(original, original, pieces, 0); + } + } + } +} +function parse_host_within_brackets(uri_string, pieces) { + return parse_host_within_brackets_loop(uri_string, uri_string, pieces, 0); +} +function parse_host(uri_string, pieces) { + let $ = uri_string.charCodeAt(0); + if ($ === 91) { + return parse_host_within_brackets(uri_string, pieces); + } else if ($ === 58) { + let pieces$1 = new Uri(pieces.scheme, pieces.userinfo, new Some(""), pieces.port, pieces.path, pieces.query, pieces.fragment); + return parse_port(uri_string, pieces$1); + } else if (uri_string === "") { + return new Ok(new Uri(pieces.scheme, pieces.userinfo, new Some(""), pieces.port, pieces.path, pieces.query, pieces.fragment)); + } else { + return parse_host_outside_of_brackets(uri_string, pieces); + } +} +function parse_userinfo_loop(loop$original, loop$uri_string, loop$pieces, loop$size) { + while (true) { + let original = loop$original; + let uri_string = loop$uri_string; + let pieces = loop$pieces; + let size3 = loop$size; + let $ = uri_string.charCodeAt(0); + if ($ === 64) { + if (size3 === 0) { + let rest = uri_string.slice(1); + return parse_host(rest, pieces); + } else { + let rest = uri_string.slice(1); + let userinfo = string_codeunit_slice(original, 0, size3); + let pieces$1 = new Uri(pieces.scheme, new Some(userinfo), pieces.host, pieces.port, pieces.path, pieces.query, pieces.fragment); + return parse_host(rest, pieces$1); + } + } else if (uri_string === "") { + return parse_host(original, pieces); + } else if ($ === 47) { + return parse_host(original, pieces); + } else if ($ === 63) { + return parse_host(original, pieces); + } else if ($ === 35) { + return parse_host(original, pieces); + } else { + let $1 = pop_codeunit(uri_string); + let rest = $1[1]; + loop$original = original; + loop$uri_string = rest; + loop$pieces = pieces; + loop$size = size3 + 1; + } + } +} +function parse_authority_pieces(string6, pieces) { + return parse_userinfo_loop(string6, string6, pieces, 0); +} +function parse_authority_with_slashes(uri_string, pieces) { + if (uri_string === "//") { + return new Ok(new Uri(pieces.scheme, pieces.userinfo, new Some(""), pieces.port, pieces.path, pieces.query, pieces.fragment)); + } else if (uri_string.startsWith("//")) { + let rest = uri_string.slice(2); + return parse_authority_pieces(rest, pieces); + } else { + return parse_path(uri_string, pieces); + } +} +function parse_scheme_loop(loop$original, loop$uri_string, loop$pieces, loop$size) { + while (true) { + let original = loop$original; + let uri_string = loop$uri_string; + let pieces = loop$pieces; + let size3 = loop$size; + let $ = uri_string.charCodeAt(0); + if ($ === 47) { + if (size3 === 0) { + return parse_authority_with_slashes(uri_string, pieces); + } else { + let scheme = string_codeunit_slice(original, 0, size3); + let pieces$1 = new Uri(new Some(lowercase(scheme)), pieces.userinfo, pieces.host, pieces.port, pieces.path, pieces.query, pieces.fragment); + return parse_authority_with_slashes(uri_string, pieces$1); + } + } else if ($ === 63) { + if (size3 === 0) { + let rest = uri_string.slice(1); + return parse_query_with_question_mark(rest, pieces); + } else { + let rest = uri_string.slice(1); + let scheme = string_codeunit_slice(original, 0, size3); + let pieces$1 = new Uri(new Some(lowercase(scheme)), pieces.userinfo, pieces.host, pieces.port, pieces.path, pieces.query, pieces.fragment); + return parse_query_with_question_mark(rest, pieces$1); + } + } else if ($ === 35) { + if (size3 === 0) { + let rest = uri_string.slice(1); + return parse_fragment(rest, pieces); + } else { + let rest = uri_string.slice(1); + let scheme = string_codeunit_slice(original, 0, size3); + let pieces$1 = new Uri(new Some(lowercase(scheme)), pieces.userinfo, pieces.host, pieces.port, pieces.path, pieces.query, pieces.fragment); + return parse_fragment(rest, pieces$1); + } + } else if ($ === 58) { + if (size3 === 0) { + return new Error2(undefined); + } else { + let rest = uri_string.slice(1); + let scheme = string_codeunit_slice(original, 0, size3); + let pieces$1 = new Uri(new Some(lowercase(scheme)), pieces.userinfo, pieces.host, pieces.port, pieces.path, pieces.query, pieces.fragment); + return parse_authority_with_slashes(rest, pieces$1); + } + } else if (uri_string === "") { + return new Ok(new Uri(pieces.scheme, pieces.userinfo, pieces.host, pieces.port, original, pieces.query, pieces.fragment)); + } else { + let $1 = pop_codeunit(uri_string); + let rest = $1[1]; + loop$original = original; + loop$uri_string = rest; + loop$pieces = pieces; + loop$size = size3 + 1; + } + } +} +function parse2(uri_string) { + return parse_scheme_loop(uri_string, uri_string, empty3, 0); +} +function to_string5(uri) { + let _block; + let $ = uri.scheme; + if ($ instanceof Some) { + let scheme = $[0]; + _block = scheme + ":"; + } else { + _block = ""; + } + let out = _block; + let _block$1; + let $1 = uri.host; + if ($1 instanceof Some) { + let host = $1[0]; + let out$12 = out + "//"; + let _block$22; + let $22 = uri.userinfo; + if ($22 instanceof Some) { + let userinfo = $22[0]; + _block$22 = out$12 + userinfo + "@"; + } else { + _block$22 = out$12; + } + let out$22 = _block$22; + let out$32 = out$22 + host; + let _block$32; + let $32 = uri.port; + if ($32 instanceof Some) { + let port = $32[0]; + _block$32 = out$32 + ":" + to_string(port); + } else { + _block$32 = out$32; + } + let out$4 = _block$32; + let _block$4; + let $4 = uri.path; + if ($4 === "") { + _block$4 = out$4; + } else if ($4.charCodeAt(0) === 47) { + _block$4 = out$4 + uri.path; + } else { + _block$4 = out$4 + "/" + uri.path; + } + let out$5 = _block$4; + _block$1 = out$5; + } else { + _block$1 = out + uri.path; + } + let out$1 = _block$1; + let _block$2; + let $2 = uri.query; + if ($2 instanceof Some) { + let query = $2[0]; + _block$2 = out$1 + "?" + query; + } else { + _block$2 = out$1; + } + let out$2 = _block$2; + let _block$3; + let $3 = uri.fragment; + if ($3 instanceof Some) { + let fragment3 = $3[0]; + _block$3 = out$2 + "#" + fragment3; + } else { + _block$3 = out$2; + } + let out$3 = _block$3; + return out$3; +} +// build/dev/javascript/gleam_http/gleam/http.mjs +class Get extends CustomType { +} +var Method$Get$const = new Get; +class Post extends CustomType { +} +var Method$Post$const = new Post; +class Head extends CustomType { +} +var Method$Head$const = new Head; +class Put extends CustomType { +} +var Method$Put$const = new Put; +class Delete extends CustomType { +} +var Method$Delete$const = new Delete; +class Trace extends CustomType { +} +var Method$Trace$const = new Trace; +class Connect extends CustomType { +} +var Method$Connect$const = new Connect; +class Options extends CustomType { +} +var Method$Options$const = new Options; +class Patch2 extends CustomType { +} +var Method$Patch$const = new Patch2; +class Http extends CustomType { +} +var Scheme$Http$const = new Http; +class Https extends CustomType { +} +var Scheme$Https$const = new Https; +function method_to_string(method) { + if (method instanceof Get) { + return "GET"; + } else if (method instanceof Post) { + return "POST"; + } else if (method instanceof Head) { + return "HEAD"; + } else if (method instanceof Put) { + return "PUT"; + } else if (method instanceof Delete) { + return "DELETE"; + } else if (method instanceof Trace) { + return "TRACE"; + } else if (method instanceof Connect) { + return "CONNECT"; + } else if (method instanceof Options) { + return "OPTIONS"; + } else if (method instanceof Patch2) { + return "PATCH"; + } else { + let method$1 = method[0]; + return method$1; + } +} +function scheme_to_string(scheme) { + if (scheme instanceof Http) { + return "http"; + } else { + return "https"; + } +} +function scheme_from_string(scheme) { + let $ = lowercase(scheme); + if ($ === "http") { + return new Ok(Scheme$Http$const); + } else if ($ === "https") { + return new Ok(Scheme$Https$const); + } else { + return new Error2(undefined); + } +} + +// build/dev/javascript/gleam_http/gleam/http/cookie.mjs +class Lax extends CustomType { +} +var SameSitePolicy$Lax$const = new Lax; +class Strict extends CustomType { +} +var SameSitePolicy$Strict$const = new Strict; +class None2 extends CustomType { +} +var SameSitePolicy$None$const = new None2; + +// build/dev/javascript/gleam_http/gleam/http/request.mjs +class Request extends CustomType { + constructor(method, headers, body2, scheme, host, port, path, query) { + super(); + this.method = method; + this.headers = headers; + this.body = body2; + this.scheme = scheme; + this.host = host; + this.port = port; + this.path = path; + this.query = query; + } +} +function to_uri(request) { + return new Uri(new Some(scheme_to_string(request.scheme)), Option$None$const, new Some(request.host), request.port, request.path, request.query, Option$None$const); +} +function from_uri(uri) { + return try$((() => { + let _pipe = uri.scheme; + let _pipe$1 = unwrap(_pipe, ""); + return scheme_from_string(_pipe$1); + })(), (scheme) => { + return try$((() => { + let _pipe = uri.host; + return to_result(_pipe, undefined); + })(), (host) => { + let req = new Request(Method$Get$const, List$Empty$const, "", scheme, host, uri.port, uri.path, uri.query); + return new Ok(req); + }); + }); +} +function set_header(request, key2, value3) { + let headers = key_set(request.headers, lowercase(key2), value3); + return new Request(request.method, headers, request.body, request.scheme, request.host, request.port, request.path, request.query); +} +function set_body(req, body2) { + return new Request(req.method, req.headers, body2, req.scheme, req.host, req.port, req.path, req.query); +} +function set_method(req, method) { + return new Request(method, req.headers, req.body, req.scheme, req.host, req.port, req.path, req.query); +} + +// build/dev/javascript/gleam_http/gleam/http/response.mjs +class Response extends CustomType { + constructor(status, headers, body2) { + super(); + this.status = status; + this.headers = headers; + this.body = body2; + } +} +var Response$Response = (status, headers, body2) => new Response(status, headers, body2); +function set_body2(response, body2) { + return new Response(response.status, response.headers, body2); +} +function get_header(response, key2) { + return key_find(response.headers, lowercase(key2)); +} +function map9(response, transform) { + let _pipe = response.body; + let _pipe$1 = transform(_pipe); + return ((_capture) => { + return set_body2(response, _capture); + })(_pipe$1); +} +// build/dev/javascript/gleam_fetch/gleam_fetch_ffi.mjs +async function raw_send(request) { + try { + return Result$Ok(await fetch(request)); + } catch (error) { + return Result$Error(FetchError$NetworkError(error.toString())); + } +} +function from_fetch_response(response) { + let headers = [...response.headers].reverse(); + return Response$Response(response.status, arrayToList2(headers), response); +} +function request_common(request) { + let url = to_string5(to_uri(request)); + let method = method_to_string(request.method).toUpperCase(); + let options = { + headers: make_headers(request.headers), + method + }; + return [url, options]; +} +function to_fetch_request(request) { + let [url, options] = request_common(request); + if (options.method !== "GET" && options.method !== "HEAD") + options.body = request.body; + return new globalThis.Request(url, options); +} +function make_headers(headersList) { + let headers = new globalThis.Headers; + for (let [k, v] of headersList) + headers.append(k.toLowerCase(), v); + return headers; +} +async function read_text_body(response) { + let body2; + try { + body2 = await response.body.text(); + } catch (error) { + return Result$Error(FetchError$UnableToReadBody()); + } + return Result$Ok(map9(response, () => body2)); +} +function arrayToList2(array3) { + let list4 = List$Empty(); + for (const element4 of array3) { + list4 = List$NonEmpty(element4, list4); + } + return list4; +} + +// build/dev/javascript/gleam_fetch/gleam/fetch.mjs +class NetworkError extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } +} +var FetchError$NetworkError = ($0) => new NetworkError($0); +class UnableToReadBody extends CustomType { +} +var FetchError$UnableToReadBody$const = new UnableToReadBody; +var FetchError$UnableToReadBody = () => FetchError$UnableToReadBody$const; +class InvalidJsonBody extends CustomType { +} +var FetchError$InvalidJsonBody$const = new InvalidJsonBody; +function send2(request) { + let _pipe = request; + let _pipe$1 = to_fetch_request(_pipe); + let _pipe$2 = raw_send(_pipe$1); + return try_await(_pipe$2, (resp) => { + return resolve(new Ok(from_fetch_response(resp))); + }); +} +// build/dev/javascript/rsvp/rsvp.ffi.mjs +var from_relative_url = (url_string) => { + if (!globalThis.location) + return new Error2(undefined); + const url = new URL(url_string, globalThis.location.href); + const uri = uri_from_url(url); + return new Ok(uri); +}; +var uri_from_url = (url) => { + const optional = (value3) => value3 ? new Some(value3) : new None; + return new Uri(optional(url.protocol?.slice(0, -1)), new None, optional(url.hostname), optional(url.port && Number(url.port)), url.pathname, optional(url.search?.slice(1)), optional(url.hash?.slice(1))); +}; + +// build/dev/javascript/rsvp/rsvp.mjs +class BadBody extends CustomType { +} +var Error$BadBody$const = new BadBody; +class BadUrl extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } +} +class HttpError extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } +} +class JsonError extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } +} +class NetworkError2 extends CustomType { +} +var Error$NetworkError$const = new NetworkError2; +class UnhandledResponse extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } +} +class Handler2 extends CustomType { + constructor(run2) { + super(); + this.run = run2; + } +} +function decode_json_body(response, decoder) { + let _pipe = response.body; + let _pipe$1 = parse(_pipe, decoder); + return map_error(_pipe$1, (var0) => { + return new JsonError(var0); + }); +} +function expect_ok_response(handler) { + return new Handler2((result) => { + return handler(try$(result, (response) => { + let $ = response.status; + let code2 = $; + if (code2 >= 200 && code2 < 300) { + return new Ok(response); + } else { + let code3 = $; + if (code3 >= 400 && code3 < 600) { + return new Error2(new HttpError(response)); + } else { + return new Error2(new UnhandledResponse(response)); + } + } + })); + }); +} +function expect_json_response(handler) { + return expect_ok_response((result) => { + return handler(try$(result, (response) => { + let $ = get_header(response, "content-type"); + if ($ instanceof Ok) { + let $1 = $[0]; + if ($1 === "application/json") { + return new Ok(response); + } else if ($1.startsWith("application/json;")) { + return new Ok(response); + } else { + return new Error2(new UnhandledResponse(response)); + } + } else { + return new Error2(new UnhandledResponse(response)); + } + })); + }); +} +function expect_json(decoder, handler) { + return expect_json_response((result) => { + let _pipe = result; + let _pipe$1 = try$(_pipe, (_capture) => { + return decode_json_body(_capture, decoder); + }); + return handler(_pipe$1); + }); +} +function expect_any_response(handler) { + return new Handler2(handler); +} +function reject(err, handler) { + return from2((dispatch2) => { + let _pipe = new Error2(err); + let _pipe$1 = handler.run(_pipe); + return dispatch2(_pipe$1); + }); +} +function do_send(request, handler) { + return from2((dispatch2) => { + let _pipe = send2(request); + let _pipe$1 = try_await(_pipe, read_text_body); + let _pipe$2 = map_promise(_pipe$1, (_capture) => { + return map_error(_capture, (error) => { + if (error instanceof NetworkError) { + return Error$NetworkError$const; + } else if (error instanceof UnableToReadBody) { + return Error$BadBody$const; + } else { + return Error$BadBody$const; + } + }); + }); + let _pipe$3 = rescue(_pipe$2, (_) => { + return new Error2(Error$NetworkError$const); + }); + let _pipe$4 = map_promise(_pipe$3, handler.run); + tap(_pipe$4, dispatch2); + return; + }); +} +function send3(request, handler) { + return do_send(request, handler); +} +function to_uri2(uri_string) { + let _block; + if (uri_string.startsWith("./")) { + _block = from_relative_url(uri_string); + } else if (uri_string.charCodeAt(0) === 47) { + _block = from_relative_url(uri_string); + } else { + _block = parse2(uri_string); + } + let _pipe = _block; + return replace_error(_pipe, new BadUrl(uri_string)); +} +function get3(url, handler) { + let $ = to_uri2(url); + if ($ instanceof Ok) { + let uri = $[0]; + let $1 = from_uri(uri); + if ($1 instanceof Ok) { + let request = $1[0]; + return send3(request, handler); + } else { + return reject(new BadUrl(url), handler); + } + } else { + let err = $[0]; + return reject(err, handler); + } +} +function post(url, body2, handler) { + let $ = to_uri2(url); + if ($ instanceof Ok) { + let uri = $[0]; + let $1 = from_uri(uri); + if ($1 instanceof Ok) { + let request = $1[0]; + let _pipe = request; + let _pipe$1 = set_method(_pipe, Method$Post$const); + let _pipe$2 = set_header(_pipe$1, "content-type", "application/json"); + let _pipe$3 = set_body(_pipe$2, to_string2(body2)); + return send3(_pipe$3, handler); + } else { + return reject(new BadUrl(url), handler); + } + } else { + let err = $[0]; + return reject(err, handler); + } +} +// build/dev/javascript/shared/shared.mjs +class Project extends CustomType { + constructor(id, name2, description, tasks) { + super(); + this.id = id; + this.name = name2; + this.description = description; + this.tasks = tasks; + } +} +class Task extends CustomType { + constructor(id, project_id, title2, description, status, assignee, assignees, due_date) { + super(); + this.id = id; + this.project_id = project_id; + this.title = title2; + this.description = description; + this.status = status; + this.assignee = assignee; + this.assignees = assignees; + this.due_date = due_date; + } +} +class Dashboard extends CustomType { + constructor(username, projects) { + super(); + this.username = username; + this.projects = projects; + } +} +class Credentials extends CustomType { + constructor(username, password) { + super(); + this.username = username; + this.password = password; + } +} +class NewProject extends CustomType { + constructor(name2, description) { + super(); + this.name = name2; + this.description = description; + } +} +class NewTask extends CustomType { + constructor(title2, description, assignee, assignees, due_date) { + super(); + this.title = title2; + this.description = description; + this.assignee = assignee; + this.assignees = assignees; + this.due_date = due_date; + } +} +class StatusChange extends CustomType { + constructor(status) { + super(); + this.status = status; + } +} +function task_decoder() { + return field("id", int2, (id) => { + return field("project_id", int2, (project_id) => { + return field("title", string3, (title2) => { + return field("description", string3, (description) => { + return field("status", string3, (status) => { + return field("assignee", string3, (assignee) => { + return field("assignees", string3, (assignees) => { + return field("due_date", string3, (due_date) => { + return success(new Task(id, project_id, title2, description, status, assignee, assignees, due_date)); + }); + }); + }); + }); + }); + }); + }); + }); +} +function project_decoder() { + return field("id", int2, (id) => { + return field("name", string3, (name2) => { + return field("description", string3, (description) => { + return field("tasks", list2(task_decoder()), (tasks) => { + return success(new Project(id, name2, description, tasks)); + }); + }); + }); + }); +} +function dashboard_decoder() { + return field("username", string3, (username) => { + return field("projects", list2(project_decoder()), (projects) => { + return success(new Dashboard(username, projects)); + }); + }); +} +function credentials_json(value3) { + return object2(toList([ + ["username", string4(value3.username)], + ["password", string4(value3.password)] + ])); +} +function new_project_json(value3) { + return object2(toList([ + ["name", string4(value3.name)], + ["description", string4(value3.description)] + ])); +} +function new_task_json(value3) { + return object2(toList([ + ["title", string4(value3.title)], + ["description", string4(value3.description)], + ["assignee", string4(value3.assignee)], + ["assignees", string4(value3.assignees)], + ["due_date", string4(value3.due_date)] + ])); +} +function status_change_json(value3) { + return object2(toList([["status", string4(value3.status)]])); +} +// build/dev/javascript/client/client.mjs +var FILEPATH = "src/client.gleam"; + +class Model extends CustomType { + constructor(page, dashboard, error, username, password, project_name, project_description, task_title, task_description, task_assignee, task_assignees, task_due_date) { + super(); + this.page = page; + this.dashboard = dashboard; + this.error = error; + this.username = username; + this.password = password; + this.project_name = project_name; + this.project_description = project_description; + this.task_title = task_title; + this.task_description = task_description; + this.task_assignee = task_assignee; + this.task_assignees = task_assignees; + this.task_due_date = task_due_date; + } +} + +class DashboardLoaded extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } +} +class LoginSubmitted extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } +} +class RegisterSubmitted extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } +} +class ProjectSubmitted extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } +} +class TaskSubmitted extends CustomType { + constructor($0, $1) { + super(); + this[0] = $0; + this[1] = $1; + } +} +class StatusSubmitted extends CustomType { + constructor($0, $1) { + super(); + this[0] = $0; + this[1] = $1; + } +} +class Authenticated extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } +} +class Saved extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } +} +class UsernameChanged extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } +} +class PasswordChanged extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } +} +class ProjectNameChanged extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } +} +class ProjectDescriptionChanged extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } +} +class TaskTitleChanged extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } +} +class TaskDescriptionChanged extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } +} +class TaskAssigneeChanged extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } +} +class TaskAssigneesChanged extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } +} +class TaskDueDateChanged extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } +} +class LogOut extends CustomType { +} +var Message$LogOut$const = new LogOut; +class Nothing extends CustomType { +} +var Message$Nothing$const = new Nothing; +function text_input(name2, placeholder2) { + return input(toList([name(name2), placeholder(placeholder2)])); +} +function task_view(task) { + let _block; + let $ = task.status; + if ($ === "todo") { + _block = "doing"; + } else if ($ === "doing") { + _block = "done"; + } else { + _block = "todo"; + } + let next = _block; + return div(toList([class$("task")]), toList([ + div(List$Empty$const, toList([ + strong(List$Empty$const, toList([text3(task.title)])), + p(List$Empty$const, toList([text3(task.description)])) + ])), + div(toList([class$("task-meta")]), toList([ + span(List$Empty$const, toList([text3(task.status)])), + text3("Owner: " + task.assignee), + text3("Assignees: " + task.assignees), + form(toList([ + on_submit((fields) => { + return new StatusSubmitted(task.id, fields); + }) + ]), toList([ + input(toList([ + type_("hidden"), + name("status"), + value(next) + ])), + button(List$Empty$const, toList([text3("Move to " + next)])) + ])) + ])) + ])); +} +function project_view(_, project) { + return article(toList([class$("panel")]), append(toList([ + text3("PROJECT"), + h2(List$Empty$const, toList([text3(project.name)])), + p(List$Empty$const, toList([text3(project.description)])) + ]), append(map2(project.tasks, task_view), toList([ + form(toList([ + on_submit((fields) => { + return new TaskSubmitted(project.id, fields); + }) + ]), toList([ + text_input("title", "Task title"), + text_input("assignee", "Owner"), + text_input("assignees", "Assignees"), + text_input("due_date", "Due date"), + text_input("description", "Details"), + button(List$Empty$const, toList([text3("Add task")])) + ])) + ])))); +} +function styles() { + return style(List$Empty$const, "body{margin:0;background:#f4f0e8;color:#28231e;font-family:Inter,ui-sans-serif,system-ui,sans-serif}.page{max-width:1120px;margin:auto;padding:28px 22px 72px}.auth{max-width:430px;margin:10vh auto;padding:42px;background:#fff;border:1px solid #e2d9cc;border-radius:22px;box-shadow:0 20px 60px #2d241414}.auth h1{font-size:clamp(2.4rem,8vw,4.8rem);line-height:.95;letter-spacing:-.06em;margin:14px 0}.auth form{display:grid;gap:12px;margin:26px 0 14px}.auth a{color:#b53b24;font-weight:700}.eyebrow{font-size:.72rem;letter-spacing:.16em;color:#b53b24;font-weight:800}header{display:flex;justify-content:space-between;gap:24px;align-items:start;margin-bottom:42px}header h1{font-size:clamp(2.7rem,7vw,5.5rem);line-height:.9;letter-spacing:-.07em;margin:12px 0}.hero{padding:42px;border-radius:22px;background:linear-gradient(120deg,#29241f,#594538);color:#fff;margin-bottom:20px;font-size:clamp(1.5rem,3vw,2.5rem);font-weight:800;letter-spacing:-.04em}.panel{background:#fff;border:1px solid #e2d9cc;border-radius:18px;padding:24px;margin:18px 0;box-shadow:0 12px 30px #2d24140b}.panel h2{margin:5px 0 8px;letter-spacing:-.03em}.panel>p{color:#796f64}.task{display:flex;justify-content:space-between;gap:20px;padding:17px 0;border-top:1px solid #eee8df}.task p{margin:5px 0 0;color:#796f64}.task-meta{display:flex;align-items:center;justify-content:flex-end;gap:9px;flex-wrap:wrap;color:#796f64;font-size:.82rem}.task-meta span{padding:5px 9px;border-radius:99px;background:#f0ebe3}.task-meta button{padding:7px 10px;font-size:.78rem}form{display:flex;gap:10px;flex-wrap:wrap;margin-top:22px}input{min-width:150px;flex:1;padding:12px 13px;border:1px solid #d9cfc2;border-radius:10px;background:#fffcf8;color:#28231e;font:inherit}button{border:0;border-radius:10px;background:#b53b24;color:#fff;padding:12px 17px;font:inherit;font-weight:800;cursor:pointer}button:hover{background:#902e1d}.error{color:#b53b24;font-weight:700}a{color:inherit;text-decoration:none}@media(max-width:650px){.task{display:block}.task-meta{justify-content:flex-start;margin-top:12px}header{display:block}.hero{padding:28px}}"); +} +function error_view(error) { + if (error instanceof Some) { + let message2 = error[0]; + return p(toList([class$("error")]), toList([text3(message2)])); + } else { + return none2(); + } +} +function dashboard_view(model) { + let $ = model.dashboard; + if ($ instanceof Some) { + let board = $[0]; + return main(toList([class$("page")]), append(toList([ + styles(), + header(List$Empty$const, toList([ + div(List$Empty$const, toList([ + text3("FRC 972 · IRON CLAW"), + h1(List$Empty$const, toList([text3("Team board")])) + ])), + button(toList([on_click(Message$LogOut$const)]), toList([text3("Sign out")])) + ])), + section(toList([class$("hero")]), toList([text3("wassup")])), + section(toList([class$("panel")]), toList([ + h2(List$Empty$const, toList([text3("New project")])), + form(toList([ + on_submit((var0) => { + return new ProjectSubmitted(var0); + }) + ]), toList([ + text_input("name", "Project name"), + text_input("description", "What does success look like?"), + button(List$Empty$const, toList([text3("Add project")])) + ])) + ])) + ]), map2(board.projects, (project) => { + return project_view(model, project); + }))); + } else { + return main(toList([class$("auth")]), toList([ + h1(List$Empty$const, toList([text3("Loading Iron Claw...")])), + error_view(model.error) + ])); + } +} +function auth_view(model, title2, submit, on_submit2) { + let _block; + let $ = submit === "Log in"; + if ($) { + _block = "/register"; + } else { + _block = "/login"; + } + let link = _block; + let _block$1; + let $1 = submit === "Log in"; + if ($1) { + _block$1 = "Need an account?"; + } else { + _block$1 = "Already registered?"; + } + let link_text = _block$1; + return main(toList([class$("auth")]), toList([ + styles(), + text3("FRC 972 · IRON CLAW"), + h1(List$Empty$const, toList([text3(title2)])), + p(List$Empty$const, toList([text3("google sheets, more like shmoogle shits")])), + error_view(model.error), + form(toList([on_submit(on_submit2)]), toList([ + input(toList([ + name("username"), + placeholder("Username"), + on_input((var0) => { + return new UsernameChanged(var0); + }) + ])), + input(toList([ + name("password"), + type_("password"), + placeholder("Password"), + on_input((var0) => { + return new PasswordChanged(var0); + }) + ])), + button(List$Empty$const, toList([text3(submit)])) + ])), + a(toList([href(link)]), toList([text3(link_text)])) + ])); +} +function view(model) { + let $ = model.page; + if ($ === "login") { + return auth_view(model, "Welcome back", "Log in", (var0) => { + return new LoginSubmitted(var0); + }); + } else if ($ === "register") { + return auth_view(model, "Create your account", "Create account", (var0) => { + return new RegisterSubmitted(var0); + }); + } else { + return dashboard_view(model); + } +} +function field2(fields, name2) { + let _pipe = key_find(fields, name2); + return unwrap2(_pipe, ""); +} +function auth_request(model, fields, url, _) { + let _block; + let _pipe = new Credentials(field2(fields, "username"), field2(fields, "password")); + _block = credentials_json(_pipe); + let body2 = _block; + return [ + model, + post(url, body2, expect_any_response((result) => { + return new Authenticated((() => { + let _pipe$1 = result; + return map4(_pipe$1, (response) => { + return response.body; + }); + })()); + })) + ]; +} +function update2(model, message2) { + if (message2 instanceof DashboardLoaded) { + let $ = message2[0]; + if ($ instanceof Ok) { + let value3 = $[0]; + echo("dashload good", undefined, "src/client.gleam", 103); + return [ + new Model(model.page, new Some(value3), Option$None$const, model.username, model.password, model.project_name, model.project_description, model.task_title, model.task_description, model.task_assignee, model.task_assignees, model.task_due_date), + none() + ]; + } else { + echo("dashload err", undefined, "src/client.gleam", 107); + return [ + new Model("login", model.dashboard, new Some("Please sign in to continue."), model.username, model.password, model.project_name, model.project_description, model.task_title, model.task_description, model.task_assignee, model.task_assignees, model.task_due_date), + none() + ]; + } + } else if (message2 instanceof LoginSubmitted) { + let fields = message2[0]; + return auth_request(model, fields, "/api/login", "/"); + } else if (message2 instanceof RegisterSubmitted) { + let fields = message2[0]; + return auth_request(model, fields, "/api/register", "/"); + } else if (message2 instanceof ProjectSubmitted) { + let fields = message2[0]; + let _block; + let _pipe = new NewProject(field2(fields, "name"), field2(fields, "description")); + _block = new_project_json(_pipe); + let body2 = _block; + return [ + model, + post("/api/projects", body2, expect_any_response((result) => { + return new Saved((() => { + let _pipe$1 = result; + return map4(_pipe$1, (response) => { + return response.body; + }); + })()); + })) + ]; + } else if (message2 instanceof TaskSubmitted) { + let project_id = message2[0]; + let fields = message2[1]; + let _block; + let _pipe = new NewTask(field2(fields, "title"), field2(fields, "description"), field2(fields, "assignee"), field2(fields, "assignees"), field2(fields, "due_date")); + _block = new_task_json(_pipe); + let body2 = _block; + return [ + model, + post("/api/projects/" + to_string(project_id) + "/tasks", body2, expect_any_response((result) => { + return new Saved((() => { + let _pipe$1 = result; + return map4(_pipe$1, (response) => { + return response.body; + }); + })()); + })) + ]; + } else if (message2 instanceof StatusSubmitted) { + let task_id = message2[0]; + let fields = message2[1]; + let status = field2(fields, "status"); + let _block; + let _pipe = new StatusChange(status); + _block = status_change_json(_pipe); + let body2 = _block; + return [ + model, + post("/api/tasks/" + to_string(task_id) + "/status", body2, expect_any_response((result) => { + return new Saved((() => { + let _pipe$1 = result; + return map4(_pipe$1, (response) => { + return response.body; + }); + })()); + })) + ]; + } else if (message2 instanceof Authenticated) { + let $ = message2[0]; + if ($ instanceof Ok) { + return [ + new Model("dashboard", model.dashboard, model.error, model.username, model.password, model.project_name, model.project_description, model.task_title, model.task_description, model.task_assignee, model.task_assignees, model.task_due_date), + get3("/api/dashboard", expect_json(dashboard_decoder(), (var0) => { + return new DashboardLoaded(var0); + })) + ]; + } else { + return [ + new Model(model.page, model.dashboard, new Some("Invalid username or password."), model.username, model.password, model.project_name, model.project_description, model.task_title, model.task_description, model.task_assignee, model.task_assignees, model.task_due_date), + none() + ]; + } + } else if (message2 instanceof Saved) { + let $ = message2[0]; + if ($ instanceof Ok) { + return [ + new Model(model.page, model.dashboard, model.error, model.username, model.password, "", "", "", "", "", "", ""), + get3("/api/dashboard", expect_json(dashboard_decoder(), (var0) => { + return new DashboardLoaded(var0); + })) + ]; + } else { + return [ + new Model(model.page, model.dashboard, new Some("The request could not be saved."), model.username, model.password, model.project_name, model.project_description, model.task_title, model.task_description, model.task_assignee, model.task_assignees, model.task_due_date), + none() + ]; + } + } else if (message2 instanceof UsernameChanged) { + let value3 = message2[0]; + return [ + new Model(model.page, model.dashboard, model.error, value3, model.password, model.project_name, model.project_description, model.task_title, model.task_description, model.task_assignee, model.task_assignees, model.task_due_date), + none() + ]; + } else if (message2 instanceof PasswordChanged) { + let value3 = message2[0]; + return [ + new Model(model.page, model.dashboard, model.error, model.username, value3, model.project_name, model.project_description, model.task_title, model.task_description, model.task_assignee, model.task_assignees, model.task_due_date), + none() + ]; + } else if (message2 instanceof ProjectNameChanged) { + let value3 = message2[0]; + return [ + new Model(model.page, model.dashboard, model.error, model.username, model.password, value3, model.project_description, model.task_title, model.task_description, model.task_assignee, model.task_assignees, model.task_due_date), + none() + ]; + } else if (message2 instanceof ProjectDescriptionChanged) { + let value3 = message2[0]; + return [ + new Model(model.page, model.dashboard, model.error, model.username, model.password, model.project_name, value3, model.task_title, model.task_description, model.task_assignee, model.task_assignees, model.task_due_date), + none() + ]; + } else if (message2 instanceof TaskTitleChanged) { + let value3 = message2[0]; + return [ + new Model(model.page, model.dashboard, model.error, model.username, model.password, model.project_name, model.project_description, value3, model.task_description, model.task_assignee, model.task_assignees, model.task_due_date), + none() + ]; + } else if (message2 instanceof TaskDescriptionChanged) { + let value3 = message2[0]; + return [ + new Model(model.page, model.dashboard, model.error, model.username, model.password, model.project_name, model.project_description, model.task_title, value3, model.task_assignee, model.task_assignees, model.task_due_date), + none() + ]; + } else if (message2 instanceof TaskAssigneeChanged) { + let value3 = message2[0]; + return [ + new Model(model.page, model.dashboard, model.error, model.username, model.password, model.project_name, model.project_description, model.task_title, model.task_description, value3, model.task_assignees, model.task_due_date), + none() + ]; + } else if (message2 instanceof TaskAssigneesChanged) { + let value3 = message2[0]; + return [ + new Model(model.page, model.dashboard, model.error, model.username, model.password, model.project_name, model.project_description, model.task_title, model.task_description, model.task_assignee, value3, model.task_due_date), + none() + ]; + } else if (message2 instanceof TaskDueDateChanged) { + let value3 = message2[0]; + return [ + new Model(model.page, model.dashboard, model.error, model.username, model.password, model.project_name, model.project_description, model.task_title, model.task_description, model.task_assignee, model.task_assignees, value3), + none() + ]; + } else if (message2 instanceof LogOut) { + return [ + new Model("login", model.dashboard, model.error, model.username, model.password, model.project_name, model.project_description, model.task_title, model.task_description, model.task_assignee, model.task_assignees, model.task_due_date), + get3("/api/logout", expect_ok_response((_) => { + return Message$Nothing$const; + })) + ]; + } else { + return [model, none()]; + } +} +function current_path() { + let _pipe = self(); + let _pipe$1 = location(_pipe); + return pathname(_pipe$1); +} +function init(_) { + let _block; + let $ = current_path(); + if ($ === "/login") { + _block = "login"; + } else if ($ === "/register") { + _block = "register"; + } else { + _block = "dashboard"; + } + let page = _block; + echo(page, undefined, "src/client.gleam", 68); + let model = new Model(page, Option$None$const, Option$None$const, "", "", "", "", "", "", "", "", ""); + return auth_request(model, List$Empty$const, "/api/login", "/"); +} +function main2() { + let app = application(init, update2, view); + let $ = start4(app, "#app", Option$None$const); + if (!($ instanceof Ok)) { + throw makeError("let_assert", FILEPATH, "client", 18, "main", "Pattern match failed, no pattern matched the value.", { value: $, start: 421, end: 471, pattern_start: 432, pattern_end: 437 }); + } + return; +} +function echo(value3, message2, file, line) { + const grey = "\x1B[90m"; + const reset_color = "\x1B[39m"; + const file_line = `${file}:${line}`; + const inspector = new Echo$Inspector; + const string_value = inspector.inspect(value3); + const string_message = message2 === undefined ? "" : " " + message2; + if (globalThis.process?.stderr?.write) { + const string6 = `${grey}${file_line}${reset_color}${string_message} +${string_value} +`; + globalThis.process.stderr.write(string6); + } else if (globalThis.Deno) { + const string6 = `${grey}${file_line}${reset_color}${string_message} +${string_value} +`; + globalThis.Deno.stderr.writeSync(new TextEncoder().encode(string6)); + } else { + const string6 = `${file_line}${string_message} +${string_value}`; + globalThis.console.log(string6); + } + return value3; +} + +class Echo$Inspector { + #references = new globalThis.Set; + #isDict(value3) { + try { + const empty_dict = make(); + const dict_class = empty_dict.constructor; + return value3 instanceof dict_class; + } catch { + return false; + } + } + #float(float3) { + const string6 = float3.toString().replace("+", ""); + if (string6.indexOf(".") >= 0) { + return string6; + } else { + const index5 = string6.indexOf("e"); + if (index5 >= 0) { + return string6.slice(0, index5) + ".0" + string6.slice(index5); + } else { + return string6 + ".0"; + } + } + } + inspect(v) { + const t = typeof v; + if (v === true) + return "True"; + if (v === false) + return "False"; + if (v === null) + return "//js(null)"; + if (v === undefined) + return "Nil"; + if (t === "string") + return this.#string(v); + if (t === "bigint" || globalThis.Number.isInteger(v)) + return v.toString(); + if (t === "number") + return this.#float(v); + if (v instanceof UtfCodepoint) + return this.#utfCodepoint(v); + if (v instanceof BitArray) + return this.#bit_array(v); + if (v instanceof globalThis.RegExp) + return `//js(${v})`; + if (v instanceof globalThis.Date) + return `//js(Date("${v.toISOString()}"))`; + if (v instanceof globalThis.Error) + return `//js(${v.toString()})`; + if (v instanceof globalThis.Function) { + const args = []; + for (const i of globalThis.Array(v.length).keys()) + args.push(globalThis.String.fromCharCode(i + 97)); + return `//fn(${args.join(", ")}) { ... }`; + } + if (this.#references.size === this.#references.add(v).size) { + return "//js(circular reference)"; + } + let printed; + if (globalThis.Array.isArray(v)) { + printed = `#(${v.map((v2) => this.inspect(v2)).join(", ")})`; + } else if (v instanceof List) { + printed = this.#list(v); + } else if (v instanceof CustomType) { + printed = this.#customType(v); + } else if (this.#isDict(v)) { + printed = this.#dict(v); + } else if (v instanceof Set) { + return `//js(Set(${[...v].map((v2) => this.inspect(v2)).join(", ")}))`; + } else { + printed = this.#object(v); + } + this.#references.delete(v); + return printed; + } + #object(v) { + const name2 = globalThis.Object.getPrototypeOf(v)?.constructor?.name || "Object"; + const props = []; + for (const k of globalThis.Object.keys(v)) { + props.push(`${this.inspect(k)}: ${this.inspect(v[k])}`); + } + const body2 = props.length ? " " + props.join(", ") + " " : ""; + const head = name2 === "Object" ? "" : name2 + " "; + return `//js(${head}{${body2}})`; + } + #dict(map10) { + let body2 = "dict.from_list(["; + let first = true; + let key_value_pairs = fold(map10, [], (pairs, key2, value3) => { + pairs.push([key2, value3]); + return pairs; + }); + key_value_pairs.sort(); + key_value_pairs.forEach(([key2, value3]) => { + if (!first) + body2 = body2 + ", "; + body2 = body2 + "#(" + this.inspect(key2) + ", " + this.inspect(value3) + ")"; + first = false; + }); + return body2 + "])"; + } + #customType(record) { + const props = globalThis.Object.keys(record).map((label) => { + const value3 = this.inspect(record[label]); + return isNaN(parseInt(label)) ? `${label}: ${value3}` : value3; + }).join(", "); + return props ? `${record.constructor.name}(${props})` : record.constructor.name; + } + #list(list4) { + if (list4 instanceof Empty) { + return "[]"; + } + let char_out = 'charlist.from_string("'; + let list_out = "["; + let current = list4; + while (current instanceof NonEmpty) { + let element4 = current.head; + current = current.tail; + if (list_out !== "[") { + list_out += ", "; + } + list_out += this.inspect(element4); + if (char_out) { + if (globalThis.Number.isInteger(element4) && element4 >= 32 && element4 <= 126) { + char_out += globalThis.String.fromCharCode(element4); + } else { + char_out = null; + } + } + } + if (char_out) { + return char_out + '")'; + } else { + return list_out + "]"; + } + } + #string(str) { + let new_str = '"'; + for (let i = 0;i < str.length; i++) { + const char = str[i]; + switch (char) { + case ` +`: + new_str += "\\n"; + break; + case "\r": + new_str += "\\r"; + break; + case "\t": + new_str += "\\t"; + break; + case "\f": + new_str += "\\f"; + break; + case "\\": + new_str += "\\\\"; + break; + case '"': + new_str += "\\\""; + break; + default: + if (char < " " || char > "~" && char < " ") { + new_str += "\\u{" + char.charCodeAt(0).toString(16).toUpperCase().padStart(4, "0") + "}"; + } else { + new_str += char; + } + } + } + new_str += '"'; + return new_str; + } + #utfCodepoint(codepoint2) { + return `//utfcodepoint(${globalThis.String.fromCodePoint(codepoint2.value)})`; + } + #bit_array(bits2) { + if (bits2.bitSize === 0) { + return "<<>>"; + } + let acc = "<<"; + for (let i = 0;i < bits2.byteSize - 1; i++) { + acc += bits2.byteAt(i).toString(); + acc += ", "; + } + if (bits2.byteSize * 8 === bits2.bitSize) { + acc += bits2.byteAt(bits2.byteSize - 1).toString(); + } else { + const trailingBitsCount = bits2.bitSize % 8; + acc += bits2.byteAt(bits2.byteSize - 1) >> 8 - trailingBitsCount; + acc += `:size(${trailingBitsCount})`; + } + acc += ">>"; + return acc; + } +} + +// .lustre/build/client.mjs +main2(); diff --git a/server/test/server_test.gleam b/server/test/server_test.gleam new file mode 100644 index 0000000..fba3c88 --- /dev/null +++ b/server/test/server_test.gleam @@ -0,0 +1,13 @@ +import gleeunit + +pub fn main() -> Nil { + gleeunit.main() +} + +// gleeunit test functions end in `_test` +pub fn hello_world_test() { + let name = "Joe" + let greeting = "Hello, " <> name <> "!" + + assert greeting == "Hello, Joe!" +} diff --git a/shared/.gitignore b/shared/.gitignore new file mode 100644 index 0000000..599be4e --- /dev/null +++ b/shared/.gitignore @@ -0,0 +1,4 @@ +*.beam +*.ez +/build +erl_crash.dump diff --git a/shared/README.md b/shared/README.md new file mode 100644 index 0000000..dd2354b --- /dev/null +++ b/shared/README.md @@ -0,0 +1,24 @@ +# shared + +[![Package Version](https://img.shields.io/hexpm/v/shared)](https://hex.pm/packages/shared) +[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://shared.hexdocs.pm/) + +```sh +gleam add shared@1 +``` +```gleam +import shared + +pub fn main() -> Nil { + // TODO: An example of the project in use +} +``` + +Further documentation can be found at . + +## Development + +```sh +gleam run # Run the project +gleam test # Run the tests +``` diff --git a/shared/gleam.toml b/shared/gleam.toml new file mode 100644 index 0000000..149e633 --- /dev/null +++ b/shared/gleam.toml @@ -0,0 +1,21 @@ +name = "shared" +version = "1.0.0" + +# Fill out these fields if you intend to generate HTML documentation or publish +# your project to the Hex package manager. +# +# description = "" +# licences = ["Apache-2.0"] +# repository = { type = "github", user = "", repo = "" } +# links = [{ title = "Website", href = "" }] +# +# For a full reference of all the available options, you can have a look at +# https://gleam.run/writing-gleam/gleam-toml/. + +[dependencies] +gleam_stdlib = ">= 1.0.0 and < 2.0.0" +gleam_json = ">= 3.1.0 and < 4.0.0" +simplifile = ">= 2.7.0 and < 3.0.0" + +[dev_dependencies] +gleeunit = ">= 1.0.0 and < 2.0.0" diff --git a/shared/manifest.toml b/shared/manifest.toml new file mode 100644 index 0000000..34ff7c6 --- /dev/null +++ b/shared/manifest.toml @@ -0,0 +1,21 @@ +# Do not manually edit this file, it is managed by Gleam. +# +# This file locks the dependency versions used, to make your build +# deterministic and to prevent unexpected versions from being included +# in your application. +# +# You should check this file into your source control repository. + +packages = [ + { name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" }, + { name = "gleam_json", version = "3.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "44FDAA8847BE8FC48CA7A1C089706BD54BADCC4C45B237A992EDDF9F2CDB2836" }, + { name = "gleam_stdlib", version = "1.0.5", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "CEE5B6C076A85B45F60C585F4316C63EC8B7127C119D5738C3958A9C4D50404E" }, + { name = "gleeunit", version = "1.11.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "EC31ABA74256AEA531EDF8169931D775BBB384FED0A8A1BDC4DD9354E3E21826" }, + { name = "simplifile", version = "2.7.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "A2727627B063E87351934C7F7F008F2D1FDB16F6DE0B8C79F9E46459CFC9C164" }, +] + +[requirements] +gleam_json = { version = ">= 3.1.0 and < 4.0.0" } +gleam_stdlib = { version = ">= 1.0.0 and < 2.0.0" } +gleeunit = { version = ">= 1.0.0 and < 2.0.0" } +simplifile = { version = ">= 2.7.0 and < 3.0.0" } diff --git a/shared/src/shared.gleam b/shared/src/shared.gleam new file mode 100644 index 0000000..7aaf0fd --- /dev/null +++ b/shared/src/shared.gleam @@ -0,0 +1,155 @@ +import gleam/dynamic/decode +import gleam/json + +pub type Project { + Project(id: Int, name: String, description: String, tasks: List(Task)) +} + +pub type Task { + Task( + id: Int, + project_id: Int, + title: String, + description: String, + status: String, + assignee: String, + assignees: String, + due_date: String, + ) +} + +pub type Dashboard { + Dashboard(username: String, projects: List(Project)) +} + +pub type Credentials { + Credentials(username: String, password: String) +} + +pub type NewProject { + NewProject(name: String, description: String) +} + +pub type NewTask { + NewTask( + title: String, + description: String, + assignee: String, + assignees: String, + due_date: String, + ) +} + +pub type StatusChange { + StatusChange(status: String) +} + +pub fn dashboard_decoder() -> decode.Decoder(Dashboard) { + use username <- decode.field("username", decode.string) + use projects <- decode.field("projects", decode.list(project_decoder())) + decode.success(Dashboard(username:, projects:)) +} + +fn project_decoder() -> decode.Decoder(Project) { + use id <- decode.field("id", decode.int) + use name <- decode.field("name", decode.string) + use description <- decode.field("description", decode.string) + use tasks <- decode.field("tasks", decode.list(task_decoder())) + decode.success(Project(id:, name:, description:, tasks:)) +} + +fn task_decoder() -> decode.Decoder(Task) { + use id <- decode.field("id", decode.int) + use project_id <- decode.field("project_id", decode.int) + use title <- decode.field("title", decode.string) + use description <- decode.field("description", decode.string) + use status <- decode.field("status", decode.string) + use assignee <- decode.field("assignee", decode.string) + use assignees <- decode.field("assignees", decode.string) + use due_date <- decode.field("due_date", decode.string) + decode.success(Task(id:, project_id:, title:, description:, status:, assignee:, assignees:, due_date:)) +} + +pub fn credentials_decoder() -> decode.Decoder(Credentials) { + use username <- decode.field("username", decode.string) + use password <- decode.field("password", decode.string) + decode.success(Credentials(username:, password:)) +} + +pub fn new_project_decoder() -> decode.Decoder(NewProject) { + use name <- decode.field("name", decode.string) + use description <- decode.field("description", decode.string) + decode.success(NewProject(name:, description:)) +} + +pub fn new_task_decoder() -> decode.Decoder(NewTask) { + use title <- decode.field("title", decode.string) + use description <- decode.field("description", decode.string) + use assignee <- decode.field("assignee", decode.string) + use assignees <- decode.field("assignees", decode.string) + use due_date <- decode.field("due_date", decode.string) + decode.success(NewTask(title:, description:, assignee:, assignees:, due_date:)) +} + +pub fn status_change_decoder() -> decode.Decoder(StatusChange) { + use status <- decode.field("status", decode.string) + decode.success(StatusChange(status:)) +} + +pub fn dashboard_json(value: Dashboard) -> json.Json { + let Dashboard(username:, projects:) = value + json.object([ + #("username", json.string(username)), + #("projects", json.array(projects, project_json)), + ]) +} + +fn project_json(value: Project) -> json.Json { + json.object([ + #("id", json.int(value.id)), + #("name", json.string(value.name)), + #("description", json.string(value.description)), + #("tasks", json.array(value.tasks, task_json)), + ]) +} + +fn task_json(value: Task) -> json.Json { + json.object([ + #("id", json.int(value.id)), + #("project_id", json.int(value.project_id)), + #("title", json.string(value.title)), + #("description", json.string(value.description)), + #("status", json.string(value.status)), + #("assignee", json.string(value.assignee)), + #("assignees", json.string(value.assignees)), + #("due_date", json.string(value.due_date)), + ]) +} + +pub fn credentials_json(value: Credentials) -> json.Json { + json.object([ + #("username", json.string(value.username)), + #("password", json.string(value.password)), + ]) +} + +pub fn new_project_json(value: NewProject) -> json.Json { + json.object([ + #("name", json.string(value.name)), + #("description", json.string(value.description)), + ]) +} + +pub fn new_task_json(value: NewTask) -> json.Json { + json.object([ + #("title", json.string(value.title)), + #("description", json.string(value.description)), + #("assignee", json.string(value.assignee)), + #("assignees", json.string(value.assignees)), + #("due_date", json.string(value.due_date)), + ]) +} + +pub fn status_change_json(value: StatusChange) -> json.Json { + json.object([#("status", json.string(value.status))]) +} diff --git a/shared/test/shared_test.gleam b/shared/test/shared_test.gleam new file mode 100644 index 0000000..fba3c88 --- /dev/null +++ b/shared/test/shared_test.gleam @@ -0,0 +1,13 @@ +import gleeunit + +pub fn main() -> Nil { + gleeunit.main() +} + +// gleeunit test functions end in `_test` +pub fn hello_world_test() { + let name = "Joe" + let greeting = "Hello, " <> name <> "!" + + assert greeting == "Hello, Joe!" +} -- 2.47.3