From 3824b62eed9f0e376c226dbb8f93287cd8cddf37 Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Fri, 24 Jan 2025 15:48:08 +1100 Subject: [PATCH 1/3] upgrade syntax, weaver, basic-cli --- CodeGen.roc | 259 +++++++------ Parser.roc | 712 +++++++++++++++++++---------------- benchmarks/Pages.roc | 395 +++++++++---------- benchmarks/output.roc | 14 +- examples/basePage/Pages.roc | 34 +- examples/basePage/server.roc | 44 ++- examples/blog/Format.roc | 22 +- examples/blog/Pages.roc | 123 +++--- examples/blog/server.roc | 43 ++- rtl.roc | 232 ++++++------ snapshots/ExpectedPages.roc | 84 +++-- snapshots/Math.roc | 2 +- snapshots/output.roc | 14 +- 13 files changed, 1066 insertions(+), 912 deletions(-) diff --git a/CodeGen.roc b/CodeGen.roc index fe12d00..1bc952f 100644 --- a/CodeGen.roc +++ b/CodeGen.roc @@ -3,62 +3,74 @@ module [generate] import Parser exposing [Node] generate : List { name : Str, nodes : List Node } -> Str -generate = \templates -> +generate = |templates| functions = - List.map templates render_template - |> Str.joinWith "\n\n" + List.map(templates, render_template) + |> Str.join_with("\n\n") names = templates - |> List.map \template -> " $(template.name)," - |> Str.joinWith "\n" + |> List.map(|template| " ${template.name},") + |> Str.join_with("\n") imports = templates - |> List.walk (Set.empty {}) \acc, template -> Set.union acc (module_imports template) - |> Set.toList - |> List.map \module_import -> "import $(module_import)" - |> Str.joinWith "\n" + |> List.walk(Set.empty({}), |acc, template| Set.union(acc, module_imports(template))) + |> Set.to_list + |> List.map(|module_import| "import ${module_import}") + |> Str.join_with("\n") # If we included escapeHtml in every module, templates without interpolations would # trigger a warning when running roc check for escapeHtml not being used. - requires_escape_html = List.any templates \{ nodes } -> - contains_interpolation nodes + requires_escape_html = List.any( + templates, + |{ nodes }| + contains_interpolation(nodes), + ) """ ## Generated by RTL https://github.com/isaacvando/rtl module [ - $(names) + ${names} ] - $(imports) + ${imports} - $(functions) - $(if requires_escape_html then escape_html else "") + ${functions} + ${if requires_escape_html then escape_html else ""} """ -module_imports = \template -> +module_imports = |template| template.nodes - |> List.walk (Set.empty {}) \acc, n -> - when n is - ModuleImport m -> Set.insert acc m - _ -> acc + |> List.walk( + Set.empty({}), + |acc, n| + when n is + ModuleImport(m) -> Set.insert(acc, m) + _ -> acc, + ) contains_interpolation : List Node -> Bool -contains_interpolation = \nodes -> - List.any nodes \node -> - when node is - Interpolation _ -> Bool.true - Conditional { true_branch, false_branch } -> - contains_interpolation true_branch || contains_interpolation false_branch - - Sequence { body } -> contains_interpolation body - WhenIs { cases } -> - List.any cases \case -> - contains_interpolation case.branch - - Text _ | RawInterpolation _ | ModuleImport _ -> Bool.false +contains_interpolation = |nodes| + List.any( + nodes, + |node| + when node is + Interpolation(_) -> Bool.true + Conditional({ true_branch, false_branch }) -> + contains_interpolation(true_branch) or contains_interpolation(false_branch) + + Sequence({ body }) -> contains_interpolation(body) + WhenIs({ cases }) -> + List.any( + cases, + |case| + contains_interpolation(case.branch), + ) + + Text(_) | RawInterpolation(_) | ModuleImport(_) -> Bool.false, + ) escape_html = """ @@ -81,134 +93,155 @@ RenderNode : [ ] render_template : { name : Str, nodes : List Node } -> Str -render_template = \{ name, nodes } -> +render_template = |{ name, nodes }| body = - condense nodes + condense(nodes) |> render_nodes # We check if the model was used in the template so that we can ignore the parameter # if it was not used to prevent an unused field warning from showing up. """ - $(name) = \\$(if is_model_used_in_list nodes then "" else "_")model -> - $(body) + ${name} = \\${if is_model_used_in_list(nodes) then "" else "_"}model -> + ${body} """ render_nodes : List RenderNode -> Str -render_nodes = \nodes -> - when List.map nodes to_str is +render_nodes = |nodes| + when List.map(nodes, to_str) is [] -> "\"\"" |> indent [elem] -> elem blocks -> - list = blocks |> Str.joinWith ",\n" + list = blocks |> Str.join_with(",\n") """ [ - $(list) + ${list} ] |> Str.joinWith "" """ |> indent -to_str = \node -> +to_str = |node| block = when node is - Text t -> + Text(t) -> """ \""" - $(t) + ${t} \""" """ - Conditional { condition, true_branch, false_branch } -> + Conditional({ condition, true_branch, false_branch }) -> """ - if $(condition) then - $(render_nodes true_branch) + if ${condition} then + ${render_nodes(true_branch)} else - $(render_nodes false_branch) + ${render_nodes(false_branch)} """ - Sequence { item, list, body } -> + Sequence({ item, list, body }) -> """ - List.map $(list) \\$(item) -> - $(render_nodes body) + List.map ${list} \\${item} -> + ${render_nodes(body)} |> Str.joinWith "" """ - WhenIs { expression, cases } -> + WhenIs({ expression, cases }) -> branches = - List.map cases \{ pattern, branch } -> - """ - $(pattern) -> - $(render_nodes branch) - """ - |> Str.joinWith "\n" + List.map( + cases, + |{ pattern, branch }| + """ + ${pattern} -> + ${render_nodes(branch)} + """, + ) + |> Str.join_with("\n") |> indent """ - when $(expression) is - $(branches) + when ${expression} is + ${branches} """ - indent block + indent(block) condense : List Node -> List RenderNode -condense = \nodes -> - List.map nodes \node -> - when node is - RawInterpolation i -> Text "\$($(i))" - Interpolation i -> Text "\$($(i) |> escape_html)" - Text t -> - # Escape Roc string interpolations from the template - escaped = Str.replaceEach t "$" "\\$" - Text escaped - - Sequence { item, list, body } -> Sequence { item, list, body: condense body } - ModuleImport _ -> Text "" - Conditional { condition, true_branch, false_branch } -> - Conditional { - condition, - true_branch: condense true_branch, - false_branch: condense false_branch, - } - - WhenIs { expression, cases } -> - WhenIs { - expression, - cases: List.map cases \{ pattern, branch } -> - { pattern, branch: condense branch }, - } - |> List.walk [] \state, elem -> - when (state, elem) is - ([.. as rest, Text x], Text y) -> - combined = Str.concat x y |> Text - rest |> List.append combined - - _ -> List.append state elem - -is_model_used_in_list = \nodes -> - List.any nodes is_model_used_in_node +condense = |nodes| + List.map( + nodes, + |node| + when node is + RawInterpolation(i) -> Text("\$(${i})") + Interpolation(i) -> Text("\$(${i} |> escape_html)") + Text(t) -> + # Escape Roc string interpolations from the template + escaped = Str.replace_each(t, "$", "\\$") + Text(escaped) + + Sequence({ item, list, body }) -> Sequence({ item, list, body: condense(body) }) + ModuleImport(_) -> Text("") + Conditional({ condition, true_branch, false_branch }) -> + Conditional( + { + condition, + true_branch: condense(true_branch), + false_branch: condense(false_branch), + }, + ) + + WhenIs({ expression, cases }) -> + WhenIs( + { + expression, + cases: List.map( + cases, + |{ pattern, branch }| + { pattern, branch: condense(branch) }, + ), + }, + ), + ) + |> List.walk( + [], + |state, elem| + when (state, elem) is + ([.. as rest, Text(x)], Text(y)) -> + combined = Str.concat(x, y) |> Text + rest |> List.append(combined) + + _ -> List.append(state, elem), + ) + +is_model_used_in_list = |nodes| + List.any(nodes, is_model_used_in_node) # We can't determine with full certainty if the model was used without parsing the Roc code that # is used on the template, which we don't do. This is a heuristic that just checks if any of the spots # that could reference the model contain "model". So a string literal that contains "model" could create # a false positive, but this isn't a big deal. -is_model_used_in_node = \node -> - contains_model = \str -> - Str.contains str "model" +is_model_used_in_node = |node| + contains_model = |str| + Str.contains(str, "model") when node is - Interpolation i | RawInterpolation i -> contains_model i - Conditional { condition, true_branch, false_branch } -> - contains_model condition || is_model_used_in_list true_branch || is_model_used_in_list false_branch + Interpolation(i) | RawInterpolation(i) -> contains_model(i) + Conditional({ condition, true_branch, false_branch }) -> + contains_model(condition) or is_model_used_in_list(true_branch) or is_model_used_in_list(false_branch) - Sequence { list, body } -> contains_model list || is_model_used_in_list body - WhenIs { expression, cases } -> - contains_model expression - || List.any cases \case -> - is_model_used_in_list case.branch + Sequence({ list, body }) -> contains_model(list) or is_model_used_in_list(body) + WhenIs({ expression, cases }) -> + contains_model(expression) + or List.any( + cases, + |case| + is_model_used_in_list(case.branch), + ) - Text _ | ModuleImport _ -> Bool.false + Text(_) | ModuleImport(_) -> Bool.false indent : Str -> Str -indent = \input -> - Str.splitOn input "\n" - |> List.map \str -> - Str.concat " " str - |> Str.joinWith "\n" +indent = |input| + Str.split_on(input, "\n") + |> List.map( + |str| + Str.concat(" ", str), + ) + |> Str.join_with("\n") diff --git a/Parser.roc b/Parser.roc index 5441578..e015505 100644 --- a/Parser.roc +++ b/Parser.roc @@ -11,494 +11,563 @@ Node : [ ] parse : Str -> List Node -parse = \input -> - when Str.toUtf8 input |> (many node) is - Match { input: [], val } -> combine_text_nodes val - Match _ -> crash "There is a bug! Not all input was consumed." - NoMatch -> crash "There is a bug! The parser didn't match." +parse = |input| + when Str.to_utf8(input) |> (many(node)) is + Match({ input: [], val }) -> combine_text_nodes(val) + Match(_) -> crash("There is a bug! Not all input was consumed.") + NoMatch -> crash("There is a bug! The parser didn't match.") combine_text_nodes : List Node -> List Node -combine_text_nodes = \nodes -> - List.walk nodes [] \state, elem -> - when (state, elem) is - ([.. as rest, Text t1], Text t2) -> - List.append rest (Text (Str.concat t1 t2)) - - (_, Conditional { condition, true_branch, false_branch }) -> - List.append state (Conditional { condition, true_branch: combine_text_nodes true_branch, false_branch: combine_text_nodes false_branch }) - - (_, Sequence { item, list, body }) -> - List.append state (Sequence { item, list, body: combine_text_nodes body }) - - (_, WhenIs { expression, cases }) -> - combined = WhenIs { - expression, - cases: List.map cases \{ pattern, branch } -> - { pattern, branch: combine_text_nodes branch }, - } - List.append state combined +combine_text_nodes = |nodes| + List.walk( + nodes, + [], + |state, elem| + when (state, elem) is + ([.. as rest, Text(t1)], Text(t2)) -> + List.append(rest, Text(Str.concat(t1, t2))) + + (_, Conditional({ condition, true_branch, false_branch })) -> + List.append(state, Conditional({ condition, true_branch: combine_text_nodes(true_branch), false_branch: combine_text_nodes(false_branch) })) + + (_, Sequence({ item, list, body })) -> + List.append(state, Sequence({ item, list, body: combine_text_nodes(body) })) + + (_, WhenIs({ expression, cases })) -> + combined = WhenIs( + { + expression, + cases: List.map( + cases, + |{ pattern, branch }| + { pattern, branch: combine_text_nodes(branch) }, + ), + }, + ) + List.append(state, combined) - _ -> List.append state elem + _ -> List.append(state, elem), + ) # Parsers Parser a : List U8 -> [Match { input : List U8, val : a }, NoMatch] node = - one_of [ - text Bool.false, - raw_interpolation, - interpolation, - import_module, - sequence, - when_is, - conditional, - text Bool.true, - ] + one_of( + [ + text(Bool.false), + raw_interpolation, + interpolation, + import_module, + sequence, + when_is, + conditional, + text(Bool.true), + ], + ) interpolation : Parser Node interpolation = - many_until horizontal_byte (string "}}") - |> start_with (string "{{") - |> map \(bytes, _) -> - bytes - |> unsafe_from_utf8 - |> Str.trim - |> Interpolation + many_until(horizontal_byte, string("}}")) + |> start_with(string("{{")) + |> map( + |(bytes, _)| + bytes + |> unsafe_from_utf8 + |> Str.trim + |> Interpolation, + ) import_module : Parser Node import_module = - many_until horizontal_byte (string "|}") - |> start_with (string "{|import") - |> map \(bytes, _) -> - bytes - |> unsafe_from_utf8 - |> Str.trim - |> ModuleImport + many_until(horizontal_byte, string("|}")) + |> start_with(string("{|import")) + |> map( + |(bytes, _)| + bytes + |> unsafe_from_utf8 + |> Str.trim + |> ModuleImport, + ) raw_interpolation : Parser Node raw_interpolation = - many_until horizontal_byte (string "}}}") - |> start_with (string "{{{") - |> map \(bytes, _) -> - bytes - |> unsafe_from_utf8 - |> Str.trim - |> RawInterpolation + many_until(horizontal_byte, string("}}}")) + |> start_with(string("{{{")) + |> map( + |(bytes, _)| + bytes + |> unsafe_from_utf8 + |> Str.trim + |> RawInterpolation, + ) when_is : Parser Node when_is = - many_until horizontal_byte (string " |}" |> end_with whitespace) - |> start_with (string "{|when ") - |> and_then \(expression, _) -> - - case = - many_until horizontal_byte (string " |}") - |> start_with (string "{|is ") - |> and_then \(pattern, _) -> - - many_before node (one_of [string "{|is ", string "{|endwhen|}"]) - |> map \branch -> - - { pattern: unsafe_from_utf8 pattern, branch } - - many_until case (string "{|endwhen|}") - |> map \(cases, _) -> - - WhenIs { - expression: unsafe_from_utf8 expression, - cases, - } + many_until(horizontal_byte, (string(" |}") |> end_with(whitespace))) + |> start_with(string("{|when ")) + |> and_then( + |(expression, _)| + + case = + many_until(horizontal_byte, string(" |}")) + |> start_with(string("{|is ")) + |> and_then( + |(pattern, _)| + + many_before(node, one_of([string("{|is "), string("{|endwhen|}")])) + |> map( + |branch| + + { pattern: unsafe_from_utf8(pattern), branch }, + ), + ) + + many_until(case, string("{|endwhen|}")) + |> map( + |(cases, _)| + + WhenIs( + { + expression: unsafe_from_utf8(expression), + cases, + }, + ), + ), + ) sequence : Parser Node sequence = - many_until horizontal_byte (string " : ") - |> start_with (string "{|list ") - |> and_then \(item, _) -> - - many_until horizontal_byte (string " |}") - |> and_then \(list, _) -> - - many_until node (string "{|endlist|}") - |> map \(body, _) -> - - Sequence { - item: unsafe_from_utf8 item, - list: unsafe_from_utf8 list, - body: body, - } + many_until(horizontal_byte, string(" : ")) + |> start_with(string("{|list ")) + |> and_then( + |(item, _)| + + many_until(horizontal_byte, string(" |}")) + |> and_then( + |(list, _)| + + many_until(node, string("{|endlist|}")) + |> map( + |(body, _)| + + Sequence( + { + item: unsafe_from_utf8(item), + list: unsafe_from_utf8(list), + body: body, + }, + ), + ), + ), + ) conditional = - many_until horizontal_byte (string " |}") - |> start_with (string "{|if ") - |> and_then \(condition, _) -> - - many_until node (one_of [string "{|endif|}", string "{|else|}"]) - |> and_then \(true_branch, separator) -> - - parse_false_branch = - if separator == "{|endif|}" then - \input -> Match { input, val: [] } - else - many_until node (string "{|endif|}") - |> map .0 + many_until(horizontal_byte, string(" |}")) + |> start_with(string("{|if ")) + |> and_then( + |(condition, _)| + + many_until(node, one_of([string("{|endif|}"), string("{|else|}")])) + |> and_then( + |(true_branch, separator)| + + parse_false_branch = + if separator == "{|endif|}" then + |input| Match({ input, val: [] }) + else + many_until(node, string("{|endif|}")) + |> map(.0) + + parse_false_branch + |> map( + |false_branch| + + Conditional( + { + condition: unsafe_from_utf8(condition), + true_branch, + false_branch, + }, + ), + ), + ), + ) - parse_false_branch - |> map \false_branch -> +text : Bool -> Parser Node +text = |allow_tags| + |input| + starts_with_tags = |bytes| + List.starts_with(bytes, ['{', '{']) or List.starts_with(bytes, ['{', '|']) + input_starts_with_tags = starts_with_tags(input) + if !allow_tags and input_starts_with_tags then + NoMatch + else if input_starts_with_tags then + { before, others } = List.split_at(input, 2) + (consumed, remaining) = split_when(others, starts_with_tags) - Conditional { - condition: unsafe_from_utf8 condition, - true_branch, - false_branch, - } + Match( + { + input: remaining, + val: List.concat(before, consumed) |> unsafe_from_utf8 |> Text, + }, + ) + else + (consumed, remaining) = split_when(input, starts_with_tags) -text : Bool -> Parser Node -text = \allow_tags -> \input -> - starts_with_tags = \bytes -> - List.startsWith bytes ['{', '{'] || List.startsWith bytes ['{', '|'] - input_starts_with_tags = starts_with_tags input - if !allow_tags && input_starts_with_tags then - NoMatch - else if input_starts_with_tags then - { before, others } = List.splitAt input 2 - (consumed, remaining) = split_when others starts_with_tags - - Match { - input: remaining, - val: List.concat before consumed |> unsafe_from_utf8 |> Text, - } - else - (consumed, remaining) = split_when input starts_with_tags - - Match { - input: remaining, - val: unsafe_from_utf8 consumed |> Text, - } + Match( + { + input: remaining, + val: unsafe_from_utf8(consumed) |> Text, + }, + ) split_when : List U8, (List U8 -> Bool) -> (List U8, List U8) -split_when = \bytes, pred -> - help = \acc, remaining -> +split_when = |bytes, pred| + help = |acc, remaining| when remaining is - [first, .. as rest] if !(pred remaining) -> - help (List.append acc first) rest + [first, .. as rest] if !(pred(remaining)) -> + help(List.append(acc, first), rest) _ -> (acc, remaining) - help [] bytes + help([], bytes) string : Str -> Parser Str -string = \str -> - \input -> - bytes = Str.toUtf8 str - if List.startsWith input bytes then - Match { input: List.dropFirst input (List.len bytes), val: str } +string = |str| + |input| + bytes = Str.to_utf8(str) + if List.starts_with(input, bytes) then + Match({ input: List.drop_first(input, List.len(bytes)), val: str }) else NoMatch horizontal_byte : Parser U8 -horizontal_byte = \input -> +horizontal_byte = |input| when input is - [first, .. as rest] if first != '\n' -> Match { input: rest, val: first } + [first, .. as rest] if first != '\n' -> Match({ input: rest, val: first }) _ -> NoMatch scalar : U8 -> Parser U8 -scalar = \byte -> - \input -> +scalar = |byte| + |input| when input is - [x, .. as rest] if x == byte -> Match { val: byte, input: rest } + [x, .. as rest] if x == byte -> Match({ val: byte, input: rest }) _ -> NoMatch whitespace : Parser (List U8) whitespace = - one_of [scalar ' ', scalar '\t', scalar '\n'] + one_of([scalar(' '), scalar('\t'), scalar('\n')]) |> many # Combinators start_with : Parser a, Parser * -> Parser a -start_with = \parser, start -> - and_then start \_ -> parser +start_with = |parser, start| + and_then(start, |_| parser) end_with : Parser a, Parser * -> Parser a -end_with = \parser, end -> - and_then parser \result -> end |> map \_ -> result +end_with = |parser, end| + and_then(parser, |result| end |> map(|_| result)) one_of : List (Parser a) -> Parser a -one_of = \options -> +one_of = |options| when options is - [] -> \_ -> NoMatch + [] -> |_| NoMatch [first, .. as rest] -> - \input -> - if List.isEmpty input then + |input| + if List.is_empty(input) then NoMatch else - when first input is - Match m -> Match m - NoMatch -> (one_of rest) input + when first(input) is + Match(m) -> Match(m) + NoMatch -> (one_of(rest))(input) many : Parser a -> Parser (List a) -many = \parser -> - help = \input, items -> - when parser input is - NoMatch -> Match { input: input, val: items } - Match m -> help m.input (List.append items m.val) +many = |parser| + help = |input, items| + when parser(input) is + NoMatch -> Match({ input: input, val: items }) + Match(m) -> help(m.input, List.append(items, m.val)) - \input -> help input [] + |input| help(input, []) # Match many occurances of a parser until another parser matches. Return the results of both parsers. many_until : Parser a, Parser b -> Parser (List a, b) -many_until = \parser, end -> - help = \input, items -> - when end input is - Match end_match -> Match { input: end_match.input, val: (items, end_match.val) } +many_until = |parser, end| + help = |input, items| + when end(input) is + Match(end_match) -> Match({ input: end_match.input, val: (items, end_match.val) }) NoMatch -> - when parser input is + when parser(input) is NoMatch -> NoMatch - Match m -> help m.input (List.append items m.val) + Match(m) -> help(m.input, List.append(items, m.val)) - \input -> help input [] + |input| help(input, []) # Match many occurances of a parser before another parser matches. Do not consume input for the ending parser. many_before : Parser a, Parser b -> Parser (List a) -many_before = \parser, end -> - help = \input, items -> - when end input is - Match _ -> Match { input, val: items } +many_before = |parser, end| + help = |input, items| + when end(input) is + Match(_) -> Match({ input, val: items }) NoMatch -> - when parser input is + when parser(input) is NoMatch -> NoMatch - Match m -> help m.input (List.append items m.val) + Match(m) -> help(m.input, List.append(items, m.val)) - \input -> help input [] + |input| help(input, []) and_then : Parser a, (a -> Parser b) -> Parser b -and_then = \parser, mapper -> - \input -> - when parser input is +and_then = |parser, mapper| + |input| + when parser(input) is NoMatch -> NoMatch - Match m -> (mapper m.val) m.input + Match(m) -> (mapper(m.val))(m.input) map : Parser a, (a -> b) -> Parser b -map = \parser, mapper -> - \in -> - when parser in is - Match { input, val } -> Match { input, val: mapper val } +map = |parser, mapper| + |in| + when parser(in) is + Match({ input, val }) -> Match({ input, val: mapper(val) }) NoMatch -> NoMatch -unsafe_from_utf8 = \bytes -> - when Str.fromUtf8 bytes is - Ok s -> s - Err _ -> - crash "There is a bug! I was unable to convert these bytes into a string: $(Inspect.toStr bytes)." +unsafe_from_utf8 = |bytes| + when Str.from_utf8(bytes) is + Ok(s) -> s + Err(_) -> + crash("There is a bug! I was unable to convert these bytes into a string: ${Inspect.to_str(bytes)}.") # Tests # just text expect - result = parse "foo" - result == [Text "foo"] + result = parse("foo") + result == [Text("foo")] # interpolation in paragraph expect - result = parse "

{{name}}

" - result == [Text "

", Interpolation "name", Text "

"] + result = parse("

{{name}}

") + result == [Text("

"), Interpolation("name"), Text("

")] # sneaky interpolation expect - result = parse "{{foo}bar}}" - result == [Interpolation "foo}bar"] + result = parse("{{foo}bar}}") + result == [Interpolation("foo}bar")] # raw interpolation expect - result = parse "{{{raw val}}}" - result == [RawInterpolation "raw val"] + result = parse("{{{raw val}}}") + result == [RawInterpolation("raw val")] # interpolation containing record that looks like raw interpolation expect - result = parse "{{{ foo : 10 } |> \\x -> Num.toStr x.foo}}" - result == [Interpolation "{ foo : 10 } |> \\x -> Num.toStr x.foo"] + result = parse("{{{ foo : 10 } |> \\x -> Num.toStr x.foo}}") + result == [Interpolation("{ foo : 10 } |> \\x -> Num.toStr x.foo")] # interpolation with piping expect - result = parse "{{func arg1 arg2 |> func2 arg2}}" - result == [Interpolation "func arg1 arg2 |> func2 arg2"] + result = parse("{{func arg1 arg2 |> func2 arg2}}") + result == [Interpolation("func arg1 arg2 |> func2 arg2")] # simple inline conditional expect - result = parse "{|if x > y |}foo{|endif|}" - result == [Conditional { condition: "x > y", true_branch: [Text "foo"], false_branch: [] }] + result = parse("{|if x > y |}foo{|endif|}") + result == [Conditional({ condition: "x > y", true_branch: [Text("foo")], false_branch: [] })] # conditional expect - result = parse + result = parse( """ {|if x > y |} foo {|endif|} - """ - result == [Conditional { condition: "x > y", true_branch: [Text "\nfoo\n"], false_branch: [] }] + """, + ) + result == [Conditional({ condition: "x > y", true_branch: [Text("\nfoo\n")], false_branch: [] })] # if else expect - result = parse + result = parse( """ {|if model.field |} Hello {|else|} goodbye {|endif|} - """ + """, + ) result == [ - Conditional { - condition: "model.field", - true_branch: [Text "\nHello\n"], - false_branch: [Text "\ngoodbye\n"], - }, + Conditional( + { + condition: "model.field", + true_branch: [Text("\nHello\n")], + false_branch: [Text("\ngoodbye\n")], + }, + ), ] # nested conditionals expect - result = parse + result = parse( """ {|if model.someField |} {|if Bool.false |} bar {|endif|} {|endif|} - """ + """, + ) result == [ - Conditional { - condition: "model.someField", - true_branch: [ - Text "\n", - Conditional { condition: "Bool.false", true_branch: [Text "\nbar\n"], false_branch: [] }, - Text "\n", - ], - false_branch: [], - }, + Conditional( + { + condition: "model.someField", + true_branch: [ + Text("\n"), + Conditional({ condition: "Bool.false", true_branch: [Text("\nbar\n")], false_branch: [] }), + Text("\n"), + ], + false_branch: [], + }, + ), ] # interpolation without inner spaces expect - result = parse + result = parse( """ foo bar {{model.baz}} foo - """ - result == [Text "foo\nbar\n", Interpolation "model.baz", Text "\nfoo"] + """, + ) + result == [Text("foo\nbar\n"), Interpolation("model.baz"), Text("\nfoo")] # Simple import expect - result = parse - "{|import SomeModule |}" - result == [ModuleImport "SomeModule"] + result = parse( + "{|import SomeModule |}", + ) + result == [ModuleImport("SomeModule")] # import within conditional expect - result = parse - "{|if Bool.true |}{|import SomeModule |}{|endif|}" - result == [Conditional { condition: "Bool.true", true_branch: [ModuleImport "SomeModule"], false_branch: [] }] + result = parse( + "{|if Bool.true |}{|import SomeModule |}{|endif|}", + ) + result == [Conditional({ condition: "Bool.true", true_branch: [ModuleImport("SomeModule")], false_branch: [] })] # paragraph containing conditional expect - result = parse + result = parse( """

{|if foo |} bar {|endif|}

- """ + """, + ) result == [ - Text "

\n ", - Conditional { condition: "foo", true_branch: [Text "\n bar\n "], false_branch: [] }, - Text "\n

", + Text("

\n "), + Conditional({ condition: "foo", true_branch: [Text("\n bar\n ")], false_branch: [] }), + Text("\n

"), ] # inline conditional expect - result = parse + result = parse( """
{|if model.username == "isaac" |}Hello{|endif|}
- """ + """, + ) result == [ - Text "
", - Conditional { condition: "model.username == \"isaac\"", true_branch: [Text "Hello"], false_branch: [] }, - Text "
", + Text("
"), + Conditional({ condition: "model.username == \"isaac\"", true_branch: [Text("Hello")], false_branch: [] }), + Text("
"), ] # list containing paragraph expect - result = parse + result = parse( """ {|list user : users |}

Hello {{user}}!

{|endlist|} - """ + """, + ) result == [ - Sequence { - item: "user", - list: "users", - body: [ - Text "\n

Hello ", - Interpolation "user", - Text "!

\n", - ], - }, + Sequence( + { + item: "user", + list: "users", + body: [ + Text("\n

Hello "), + Interpolation("user"), + Text("!

\n"), + ], + }, + ), ] # when is on result expect - result = parse + result = parse( """ {|when x |} {|is Err "foo" |}there was an error {|is Ok "bar" |}we are ok! {|endwhen|} - """ + """, + ) result == [ - WhenIs { - expression: "x", - cases: [ - { pattern: "Err \"foo\"", branch: [Text "there was an error\n"] }, - { pattern: "Ok \"bar\"", branch: [Text "we are ok!\n"] }, - ], - }, + WhenIs( + { + expression: "x", + cases: [ + { pattern: "Err \"foo\"", branch: [Text("there was an error\n")] }, + { pattern: "Ok \"bar\"", branch: [Text("we are ok!\n")] }, + ], + }, + ), ] # when is with single branch expect - result = parse + result = parse( """ {|when x |} {|is _ |} catch all {|endwhen|} - """ + """, + ) result == [ - WhenIs { - expression: "x", - cases: [ - { pattern: "_", branch: [Text " catch all\n"] }, - ], - }, + WhenIs( + { + expression: "x", + cases: [ + { pattern: "_", branch: [Text(" catch all\n")] }, + ], + }, + ), ] # nested when is expect - result = parse + result = parse( """ {|when (foo, bar) |} {|is (1, 2) |} @@ -508,65 +577,74 @@ expect {|is (_, _) |} hello {|endwhen|} - """ + """, + ) result == [ - WhenIs { - cases: [ - { - branch: [ - Text "\n ", - WhenIs { - cases: [{ branch: [Text " ", Interpolation "x", Text "\n "], pattern: "_" }], - expression: "x", - }, - Text "\n", - ], - pattern: "(1, 2)", - }, - { - branch: [Text "\n hello\n"], - pattern: "(_, _)", - }, - ], - expression: "(foo, bar)", - }, + WhenIs( + { + cases: [ + { + branch: [ + Text("\n "), + WhenIs( + { + cases: [{ branch: [Text(" "), Interpolation("x"), Text("\n ")], pattern: "_" }], + expression: "x", + }, + ), + Text("\n"), + ], + pattern: "(1, 2)", + }, + { + branch: [Text("\n hello\n")], + pattern: "(_, _)", + }, + ], + expression: "(foo, bar)", + }, + ), ] # parses unicode characters correctly expect - result = parse + result = parse( """ 中文繁體{{model.foo "🐱"}}πŸ™‚β€β†•οΈπŸ₯ {|if "πŸ₯" == "πŸ₯" |}foo{|endif|} - """ + """, + ) result == [ - Text "中文繁體", - Interpolation + Text("中文繁體"), + Interpolation( """ model.foo "🐱" """, - Text "πŸ™‚β€β†•οΈπŸ₯\n", - Conditional { - condition: - """ - "πŸ₯" == "πŸ₯" - """, - true_branch: [Text "foo"], - false_branch: [], - }, + ), + Text("πŸ™‚β€β†•οΈπŸ₯\n"), + Conditional( + { + condition: + """ + "πŸ₯" == "πŸ₯" + """, + true_branch: [Text("foo")], + false_branch: [], + }, + ), ] # unclosed tags are parsed as Text expect - result = parse "{|if Bool.true |}{|list model.cities |}" - result == [Text "{|if Bool.true |}{|list model.cities |}"] + result = parse("{|if Bool.true |}{|list model.cities |}") + result == [Text("{|if Bool.true |}{|list model.cities |}")] # multiline tags are not allowed expect - result = parse + result = parse( """ {{ "firstline" |> Str.concat "secondline"}} @@ -583,10 +661,11 @@ expect {|endlist|} {|import Module |} - """ + """, + ) result == [ - Text + Text( """ {{ "firstline" |> Str.concat "secondline"}} @@ -604,4 +683,5 @@ expect {|import Module |} """, + ), ] diff --git a/benchmarks/Pages.roc b/benchmarks/Pages.roc index 7ca6629..d4bfafd 100644 --- a/benchmarks/Pages.roc +++ b/benchmarks/Pages.roc @@ -1,413 +1,414 @@ ## Generated by RTL https://github.com/isaacvando/rtl module [ lorem, - ] +] -lorem = \model -> +lorem = |model| [ when model.color is Red -> """ - + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec aliquet vehicula ipsum sit amet elementum. Vivamus nec felis a augue auctor vestibulum ac in turpis. Mauris non suscipit diam. Maecenas at mauris eu mi consequat molestie sed id orci. Proin fermentum purus sit amet sapien malesuada aliquam. Pellentesque eget tellus enim. Nullam posuere dapibus mattis. Cras blandit sapien et ligula egestas, in malesuada felis placerat. Nunc interdum, eros non lacinia malesuada, tellus libero sollicitudin nisl, id euismod diam metus id erat. Maecenas ac nibh eu velit volutpat maximus eu porttitor tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc tincidunt malesuada viverra. Integer tristique, sapien in ultricies ultricies, sapien dolor tincidunt dolor, vel hendrerit nibh est quis ligula. - + """ + Blue -> """ - + Curabitur a hendrerit mi, sed ultricies arcu. In elementum quis lorem in ullamcorper. Duis sodales vestibulum turpis vel tincidunt. Etiam tincidunt felis metus, in varius magna aliquam nec. In hac habitasse platea dictumst. Maecenas rhoncus nunc ex. Suspendisse eget hendrerit ante. Fusce semper eros vestibulum nibh tempor, nec convallis neque posuere. - + """ + Green -> """ - + Phasellus finibus, mauris non varius faucibus, purus nisi accumsan risus, ut posuere magna arcu varius turpis. Aliquam quis malesuada ipsum. Sed lorem justo, porttitor sit amet lacus eget, accumsan pharetra augue. Nam sollicitudin justo eu purus viverra volutpat. Integer id facilisis nisl. Donec a libero blandit, ultricies mi id, ultrices felis. Etiam ut est ultrices, suscipit metus vitae, suscipit nibh. Vivamus diam risus, pretium quis efficitur sit amet, vestibulum eu risus. Nullam eu tempor orci, quis mollis odio. Integer id metus vitae diam elementum faucibus in vel nulla. Vestibulum rutrum ornare euismod. Donec vestibulum dapibus molestie. Nunc pulvinar, nibh ac ullamcorper aliquam, magna turpis luctus turpis, a commodo nulla augue sit amet dui. Vivamus cursus non odio quis sodales. Duis velit mi, congue at posuere dignissim, rutrum vel orci. Morbi sit amet tellus sem. - - """ - , + + """, """ - + Pellentesque imperdiet, ligula at lacinia condimentum, odio lacus egestas dolor, eget bibendum ligula tortor vitae enim. Curabitur vel dapibus nulla. Nam in lacinia ante, et interdum libero. Nam sit amet nunc vel mauris ullamcorper egestas. Suspendisse lorem purus, rutrum nec sem id, auctor vehicula ante. Aenean finibus tellus vel urna sagittis, vitae hendrerit nisl hendrerit. Vestibulum eget quam sem. Duis ac urna in magna congue cursus at non quam. Phasellus tristique neque ac metus tempor posuere. Fusce felis libero, porttitor in lorem sit amet, euismod vestibulum nulla. Mauris auctor auctor massa eu feugiat. In venenatis leo risus, id semper neque aliquam id. Phasellus ac mattis tellus. Donec tincidunt in orci quis congue. - + Nam ultrices auctor felis, eu lacinia metus aliquam ac. Ut fermentum laoreet hendrerit. Mauris sit amet nisi consequat, commodo dolor quis, tristique nulla. Ut odio eros, mattis eget risus consectetur, congue blandit urna. Sed in nulla tellus. Praesent sagittis nisl faucibus venenatis dignissim. Praesent varius ullamcorper enim, vel pretium arcu dapibus vitae. Proin nisi eros, condimentum a ultrices sagittis, rhoncus vitae ex. Donec luctus est at ipsum pulvinar tincidunt. Sed convallis nisi eget massa sollicitudin commodo. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Quisque varius fermentum felis a mollis. Sed sed laoreet odio, eu congue orci. Phasellus dictum laoreet nibh ac efficitur. Aenean accumsan ligula vitae nunc porttitor vulputate. Aenean lectus dui, porta ac urna a, laoreet blandit magna. - + Nulla mattis leo nec mollis ultricies. Nulla mollis leo id dapibus vestibulum. Vestibulum in accumsan felis, nec pulvinar nisl. Proin ut nibh ipsum. Donec tempor augue tellus, ut porttitor odio mollis eu. Duis mattis purus velit, ac pretium felis blandit et. Aenean et arcu vehicula, cursus leo non, venenatis lectus. Morbi sollicitudin vehicula eros ac rhoncus. Phasellus eget velit nisi. Nulla gravida lacinia urna eget laoreet. Maecenas non blandit erat, facilisis ultrices tortor. - + Donec malesuada ante quis posuere luctus. Duis eu odio augue. Proin laoreet tortor vitae nunc ultrices vehicula. Vivamus egestas id turpis ut lobortis. Integer consequat dapibus placerat. Curabitur vitae risus sapien. Duis condimentum mauris mattis massa facilisis congue. Aliquam dictum, odio a tristique tempus, metus lorem accumsan nisl, quis malesuada risus turpis non tortor. Vestibulum ac magna sagittis, convallis orci mollis, sagittis ligula. Proin mattis velit sollicitudin, auctor tortor sit amet, vestibulum lorem. - + Quisque sagittis enim et neque ullamcorper, in mollis tellus rhoncus. Fusce congue faucibus eros in auctor. Nulla facilisi. Nunc ultricies scelerisque tortor, in dictum dui. Duis accumsan malesuada quam nec aliquam. Vivamus mollis sem arcu, vel vehicula sapien mattis nec. Fusce cursus metus tortor, non tincidunt libero commodo nec. Integer dolor erat, ullamcorper vel aliquet nec, malesuada sed tellus. - + Nam condimentum turpis at nibh malesuada, quis pellentesque lectus posuere. Proin semper faucibus odio, quis scelerisque mi euismod a. Aenean finibus mauris eget dui euismod varius. Sed ornare risus quis elit sodales, sed ultrices lectus lacinia. Nam justo ligula, viverra sit amet risus tristique, vulputate finibus dui. Donec in ultricies sapien. Sed lobortis nulla non neque euismod, a faucibus quam pharetra. Proin varius volutpat ipsum sed aliquet. Cras tempor ligula vitae velit pulvinar, eget imperdiet purus sagittis. Mauris accumsan condimentum massa. - + Cras id molestie risus. Vivamus eleifend ac velit in placerat. Nulla sagittis elit vitae mi lacinia vehicula. Nunc dapibus neque lectus, at fringilla neque pharetra ac. Donec ultricies turpis ut mi laoreet porta. Nunc ultrices porttitor massa nec viverra. Quisque varius turpis nisi. Praesent non faucibus magna. Morbi quis nisi erat. Phasellus pulvinar nulla sodales commodo aliquam. - + Aenean sed est vitae lorem condimentum dapibus vitae volutpat ligula. Nullam ultrices lorem leo, eget fringilla elit rutrum at. Ut ultrices odio eu quam consequat tincidunt. Phasellus id tincidunt enim. Vestibulum in quam elit. Vivamus ut malesuada risus, eu viverra nisi. Morbi efficitur felis sit amet nulla congue, posuere porta leo egestas. Aliquam erat volutpat. Phasellus leo nisl, auctor non arcu vel, tempus elementum metus. Suspendisse eleifend molestie consectetur. Aliquam sed magna vitae mi commodo dictum. Mauris quis eros pharetra, venenatis lorem et, varius neque. - + Cras auctor quam purus, vitae elementum purus consequat nec. Cras orci lectus, auctor id volutpat vel, lacinia a sapien. Curabitur nulla augue, venenatis sit amet nibh non, semper euismod velit. Sed faucibus erat augue, eu vestibulum diam elementum sed. Suspendisse dignissim enim nec faucibus finibus. Sed vel ante ac est porttitor varius eget eget nisi. Cras vel aliquet magna, vel volutpat ante. Praesent in ante tristique nisl blandit volutpat ac vel urna. Curabitur pretium sit amet mi dapibus blandit. Morbi bibendum velit sit amet justo convallis, non finibus tellus bibendum. Aliquam congue nibh in magna dapibus vehicula. Pellentesque elementum malesuada libero, eu euismod tortor malesuada vel. Curabitur tempor posuere orci, non gravida nunc molestie vitae. - + Donec consequat odio at nibh congue maximus. Nulla sagittis congue sapien vitae venenatis. Duis ac elit et nibh condimentum egestas quis at velit. Suspendisse potenti. Nulla fermentum tellus diam, a ultricies dui posuere sed. Ut finibus elit id purus iaculis, in finibus libero faucibus. Pellentesque convallis leo nec elit gravida maximus. Etiam tempus, nisl ut laoreet laoreet, magna elit hendrerit neque, eu lacinia nunc lectus ac est. Sed volutpat porta lorem, eu mollis elit ultrices et. - + Vestibulum viverra scelerisque vulputate. Quisque condimentum metus vitae ipsum pretium facilisis eu nec sapien. Fusce non pharetra enim. Nulla vehicula elit justo, quis varius dui dictum a. Integer mattis lorem a libero sagittis tempor. Cras eu mi malesuada, facilisis nisl id, viverra nisi. Nullam fermentum libero a iaculis pulvinar. Duis eu lorem sit amet diam scelerisque molestie a eu ligula. - + Vestibulum tempor, mi in facilisis sollicitudin, lorem risus semper tellus, eu tincidunt ex massa sit amet sapien. Fusce commodo facilisis orci, nec fermentum augue efficitur ac. Donec fermentum orci justo, in pretium justo porta eu. Pellentesque tempus id metus at vehicula. Praesent fermentum risus at nisl placerat, vel blandit quam bibendum. In varius orci et volutpat semper. Proin mattis suscipit vestibulum. Nullam neque lorem, placerat et sapien nec, tincidunt porta ex. Vestibulum quis ante massa. Donec venenatis rutrum massa, vel dictum mi interdum sit amet. Morbi quis est in lacus feugiat hendrerit ut ut justo. - + Nullam malesuada metus pellentesque orci bibendum egestas. Nam non fermentum magna, a porta nisl. Aliquam erat volutpat. Pellentesque feugiat quam ut mollis malesuada. Quisque quis massa hendrerit, faucibus urna sit amet, porttitor nulla. Donec viverra ipsum vel suscipit accumsan. Curabitur ut ante tellus. - + Donec dapibus eros sit amet elit porttitor, ut lacinia lacus feugiat. Aenean nec lectus auctor, finibus sapien sed, scelerisque neque. Pellentesque mollis sit amet erat quis vestibulum. Nunc vel convallis nulla. Fusce eu nisl urna. Sed elementum pellentesque ante et blandit. Maecenas dolor tellus, malesuada et condimentum eget, pulvinar at ligula. Mauris suscipit purus eu pulvinar pharetra. Nulla ut mauris leo. Maecenas eu augue eget eros convallis rutrum vel eget dui. Fusce nec blandit lacus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. - + In tincidunt turpis sed urna elementum rhoncus vitae eu tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nullam sem dolor, consequat ac viverra vitae, tincidunt ut risus. Nulla facilisi. In quis ante eget lectus suscipit porta. Mauris at tellus a arcu pellentesque ullamcorper. Praesent et consequat felis. Aliquam commodo dui eu congue vestibulum. Suspendisse non varius enim. Morbi ornare est eu purus aliquet, ut consectetur libero sodales. Suspendisse accumsan suscipit tortor, non lacinia erat. Etiam vitae molestie lacus, sit amet semper eros. Proin sollicitudin molestie justo sed gravida. Pellentesque ornare sit amet quam ut accumsan. Fusce leo justo, ultrices quis orci ut, convallis efficitur dui. - + Nullam ligula libero, molestie ut dui vel, auctor congue mauris. Proin et ipsum sit amet est euismod mattis. Quisque imperdiet odio id odio consectetur, sed euismod est sollicitudin. Ut a enim libero. In interdum est efficitur rutrum molestie. Cras non facilisis neque. Nulla placerat feugiat eleifend. Nunc purus quam, ultrices et sollicitudin sed, luctus et magna. - + Integer ultricies enim placerat blandit dapibus. Nulla porta dignissim nisi quis volutpat. Praesent ac turpis porttitor, tempus tellus quis, eleifend est. Sed ut magna varius nibh laoreet tincidunt. Fusce odio nulla, pulvinar vel arcu id, blandit elementum sem. Fusce quis neque lacus. Sed fermentum dui in tortor faucibus, eget ultrices augue consectetur. Donec eu faucibus libero. Donec dictum luctus mi non cursus. Phasellus lectus orci, tincidunt in urna eget, condimentum scelerisque sem. - + Integer gravida, urna ut pellentesque sodales, odio odio volutpat augue, id pretium magna ex eu turpis. Mauris a elit luctus, bibendum massa a, posuere augue. Nam egestas, augue nec bibendum accumsan, massa ipsum malesuada dui, ut lobortis enim leo id purus. Sed in arcu sit amet nibh suscipit consequat varius vitae mauris. Etiam lacinia placerat risus, non pretium justo finibus nec. Nam hendrerit quam dui. Maecenas nec tellus eu mauris cursus fringilla. - + In magna nibh, sodales at nunc sit amet, rhoncus sodales mi. Aliquam erat volutpat. Quisque vitae mauris feugiat, laoreet ex id, dictum turpis. Suspendisse potenti. Maecenas sit amet tincidunt felis. Praesent ullamcorper quam ligula, vel hendrerit sem fringilla sed. Donec non dictum velit, sit amet blandit velit. Vivamus condimentum tellus non rutrum consequat. Donec est quam, elementum in ipsum nec, iaculis tempor elit. Sed finibus enim a purus euismod, vel porttitor turpis facilisis. Praesent suscipit vel nunc sed suscipit. Curabitur volutpat quis ligula sed convallis. Donec pretium dui libero. - + Phasellus id mollis sem, a tincidunt mi. Aliquam odio dolor, egestas sed vestibulum in, dictum vitae justo. Vestibulum ligula tortor, imperdiet eu lacus eu, viverra finibus quam. Ut convallis et eros a tristique. Donec eu magna ac est pretium pretium sit amet vel mi. Aenean bibendum massa rhoncus ex rhoncus ornare. Mauris ultrices aliquam viverra. Phasellus nec ipsum at orci malesuada porttitor tincidunt non leo. - + Aenean ullamcorper nisl augue, sit amet commodo lacus vehicula nec. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed pulvinar velit quam, id dapibus ex tincidunt ut. Nulla nec tortor et augue scelerisque tempus non sit amet massa. Vestibulum ut porta ipsum. Nam semper pellentesque mattis. Vestibulum lacus arcu, pretium sit amet finibus ac, euismod eget urna. - + Mauris et consectetur dui, et rhoncus quam. Sed fringilla mi vitae lobortis aliquam. Sed arcu lacus, commodo sit amet nisl sed, iaculis rhoncus leo. Sed ultricies quam vestibulum, blandit magna interdum, facilisis ex. Quisque diam ligula, sollicitudin vitae ullamcorper in, accumsan ac enim. Proin interdum iaculis massa at aliquam. Duis aliquet dui in venenatis ultricies. Nullam vitae iaculis nunc, sed ornare purus. - + Nullam vitae lorem ut eros fringilla accumsan. Maecenas id facilisis neque, eget rutrum justo. Suspendisse pellentesque neque quis interdum ultrices. Maecenas nec lectus ligula. Suspendisse potenti. Vestibulum metus metus, tempus id quam id, hendrerit semper orci. Sed auctor sem vel vestibulum rhoncus. Nam et porta mauris. Ut vel nisl enim. Etiam nec mollis lectus. Cras fermentum dapibus augue, ac luctus erat ullamcorper vel. Aliquam tincidunt nulla lorem, sit amet ornare enim ultricies commodo. Donec vitae nisi eget ex eleifend vulputate id ac mi. Vestibulum finibus iaculis odio a dignissim. - + Duis at sapien in massa imperdiet volutpat. Suspendisse nunc lacus, tincidunt et interdum a, accumsan quis arcu. Sed posuere ex mi, vel vulputate lacus ultricies eu. Vestibulum eu mattis lectus. Cras sed nibh pretium, vulputate libero eu, volutpat nisl. Maecenas rhoncus ut nibh non efficitur. Mauris et lorem magna. Aliquam ultrices lorem urna, id sollicitudin leo commodo eu. Vivamus iaculis ut velit eget convallis. Integer convallis risus tempus tellus accumsan hendrerit. Duis aliquet nunc nec turpis mattis dictum. Nunc hendrerit nulla vel porta venenatis. Fusce quis viverra erat. Sed vehicula luctus odio, vel elementum quam vulputate sit amet. - + Curabitur iaculis erat quis ex dignissim consequat. Nulla in fringilla massa, gravida maximus ante. Sed cursus sem a diam tempor, id porta eros pulvinar. Ut tincidunt nec ligula ac luctus. Proin ac lacus interdum elit varius malesuada eu a ante. Pellentesque non velit a metus fringilla semper. Suspendisse potenti. Ut eget ante id felis laoreet posuere et vel est. Etiam turpis urna, interdum sed arcu at, pretium lobortis nibh. Mauris congue dapibus nisi, nec vehicula sapien venenatis at. Proin vel aliquam tortor, at venenatis neque. Proin ac tincidunt urna, a ultricies velit. Nullam at odio eget lacus feugiat tempor. Pellentesque ac sodales purus. In hac habitasse platea dictumst. Aliquam enim magna, faucibus id rhoncus eu, lobortis quis nisi. - + Pellentesque vehicula cursus eros. Ut urna purus, aliquet eu dui vitae, lacinia semper nunc. Aenean luctus pulvinar risus, vel placerat metus porttitor id. Fusce nec hendrerit nibh. Aliquam erat volutpat. Mauris efficitur neque quis odio sodales vehicula. Vivamus ex mi, vulputate quis sem nec, faucibus finibus neque. Morbi aliquam enim neque, posuere luctus ex maximus a. Aliquam aliquam erat massa, at finibus tellus porttitor non. Interdum et malesuada fames ac ante ipsum primis in faucibus. In et fermentum nibh, eu pulvinar est. Suspendisse rutrum imperdiet risus vel fermentum. Aenean hendrerit sodales ante at fermentum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; - + """, if model.color == Red then """ - + Phasellus ornare pharetra tortor, eget viverra est volutpat a. Aenean dignissim augue neque, vel euismod dui pellentesque eu. Maecenas varius imperdiet arcu ut placerat. Aliquam sollicitudin urna non augue pretium viverra. Cras vitae posuere metus. Aliquam auctor, mauris in venenatis porttitor, nibh quam bibendum lorem, vel viverra nulla quam ac turpis. Cras mattis, tortor sed elementum condimentum, orci ipsum imperdiet eros, quis suscipit ligula justo auctor turpis. Morbi vitae consequat erat. Donec eu hendrerit nisi, non fringilla tortor. Quisque vestibulum, odio sit amet fermentum vulputate, felis turpis eleifend nunc, sit amet mattis tortor libero sit amet tortor. Donec dapibus purus turpis, nec bibendum elit fermentum laoreet. Donec eget odio convallis, ultricies nulla euismod, suscipit felis. Quisque nulla tellus, tincidunt vitae tincidunt vel, dictum eu nisl. - + Duis eget accumsan massa. Nulla non imperdiet purus. Nullam posuere leo id augue iaculis eleifend. Ut a pretium ex. Duis varius lectus ipsum, a hendrerit sapien ornare eget. Curabitur massa nibh, vulputate non dictum nec, sollicitudin id nulla. Donec eget scelerisque risus, ut pellentesque tellus. In hac habitasse platea dictumst. Etiam mollis nisi non quam pulvinar convallis. Praesent aliquet et augue et sollicitudin. Nullam accumsan libero non risus dictum, scelerisque pulvinar sem tincidunt. Praesent et dui vitae nunc pellentesque hendrerit sed nec leo. - + Pellentesque semper purus eros, sit amet dapibus felis auctor ac. Curabitur ac urna arcu. Proin iaculis justo magna, a interdum enim pulvinar vel. Quisque eget orci non diam efficitur accumsan eget nec quam. Duis venenatis varius fringilla. Praesent sed scelerisque nunc, in pulvinar lacus. In vel metus vel libero ornare facilisis eu at enim. Nunc non euismod dui, et varius ante. Aenean sagittis orci at tellus pharetra tempor. Nulla pretium erat risus, non vehicula dolor porta ac. Integer volutpat eros vitae egestas aliquam. Phasellus vel lectus ex. Nam ullamcorper, lorem eu mattis efficitur, augue neque dictum urna, id iaculis sapien elit sit amet nisl. Nunc non ornare purus. - + """ else """ - + In auctor ipsum turpis, ut mattis leo tempus et. Suspendisse potenti. Mauris dui arcu, feugiat in consectetur vel, convallis vitae nulla. Suspendisse aliquam porta diam eget gravida. Nulla mattis sodales dui tincidunt accumsan. Donec euismod sed lacus non malesuada. Fusce in ipsum auctor, laoreet ex sed, tincidunt turpis. Praesent arcu ipsum, elementum nec leo ut, faucibus molestie eros. Nullam convallis, tellus varius tincidunt finibus, est elit faucibus erat, sed laoreet sapien arcu ut nulla. Sed sagittis nulla ac metus rhoncus finibus. Nunc vitae porta orci. - + Donec at erat vitae nisl imperdiet lacinia eget vitae arcu. Sed vitae arcu tempus quam consequat viverra. Aliquam sodales quam at sem eleifend ullamcorper. Aenean vulputate, enim vitae tristique suscipit, massa metus laoreet erat, vel dictum orci tellus eget risus. Suspendisse ornare semper quam, in pharetra lacus bibendum at. Ut tempus rhoncus nibh sit amet iaculis. Praesent lobortis est orci, quis bibendum turpis scelerisque sit amet. - + """, """ - + Nunc auctor posuere ultrices. Aenean elementum, purus non congue dignissim, nunc nulla aliquet quam, non varius neque erat vitae erat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis dictum ex orci, sit amet tempus quam tincidunt sit amet. Phasellus eget turpis egestas, congue mi in, faucibus elit. Nunc nec mi convallis, rhoncus risus efficitur, vehicula est. Curabitur id justo dui. Maecenas aliquam, lectus vel feugiat aliquet, sapien lacus facilisis lorem, at placerat dui ante a orci. Nam sollicitudin mattis quam quis molestie. Praesent tempor rutrum libero sit amet ultrices. Mauris vulputate eu augue sed congue. Morbi lacinia ligula at lacus congue mattis. Nam efficitur ligula felis, ut congue sapien aliquam sed. - + Phasellus fringilla at purus at efficitur. Suspendisse ut lobortis sem. Vestibulum a vulputate felis, ut elementum odio. Ut semper mollis ante id mollis. Nullam nec risus non eros gravida eleifend. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec et egestas nisl. Mauris nibh lacus, dictum in augue sit amet, hendrerit bibendum metus. Cras purus massa, semper eget feugiat sed, tempor quis erat. Nulla facilisi. Pellentesque ipsum lectus, euismod quis turpis sed, rhoncus porta sapien. Pellentesque eu nunc vel elit cursus euismod a sit amet ligula. Fusce vel elementum sapien. Ut magna arcu, sagittis at tincidunt et, pretium ornare nisi. In placerat risus ac mollis feugiat. - + Nunc ac semper turpis. Sed lacinia enim vel libero placerat, eget tincidunt sem ullamcorper. Nullam eu dolor tortor. Nam viverra eget tortor quis porta. Integer viverra eu nulla vel tempor. Mauris sagittis purus eu auctor rutrum. Quisque a bibendum nisl. Praesent fermentum, libero eget efficitur pharetra, nulla enim tincidunt turpis, et vestibulum metus felis nec lacus. Donec ut gravida nisi. Phasellus aliquam sem id elit mollis scelerisque. Praesent in ligula vel augue aliquam dapibus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Morbi vitae leo neque. Vivamus id lectus non eros finibus pulvinar. - + Nulla imperdiet sollicitudin facilisis. Aliquam maximus neque lacus, et bibendum justo gravida a. Quisque ornare ullamcorper urna id finibus. Aenean nec sodales justo, sit amet auctor purus. Integer tincidunt mauris eget diam ultricies, lobortis tincidunt purus consectetur. Suspendisse in sapien nec ex ultrices dignissim sit amet eu lectus. Integer in euismod lacus. Integer ac diam ac nisi accumsan semper at vel purus. Nunc non eros elit. Sed vel mauris augue. Ut ac erat pharetra, vestibulum nulla nec, volutpat mauris. - + Ut vitae convallis dui, eu gravida metus. Phasellus porttitor sem enim, quis maximus diam consectetur vitae. Quisque faucibus commodo lectus ut imperdiet. Cras aliquam vel massa vel vulputate. Praesent fringilla et est eget bibendum. Sed aliquet dictum sem a varius. Ut et malesuada purus. In elit sapien, sagittis non nisl sed, ultrices viverra ante. In imperdiet sem eget posuere placerat. - - $(model.name |> escapeHtml) Maecenas interdum diam quis felis posuere $(model.name |> escapeHtml) blandit. Pellentesque eu arcu est. Cras auctor vitae leo a egestas. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum sed turpis ipsum. Phasellus dictum neque risus, in viverra ante tempor bibendum. Donec vitae odio faucibus, faucibus magna non, consequat enim. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec dignissim mauris dui. Integer nec enim magna. Integer semper felis eu mauris pulvinar facilisis. Vivamus ac augue quam. Aliquam viverra, risus sed vehicula posuere, sapien lorem mattis nibh, eget blandit lorem purus sit amet elit. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Sed egestas neque id tortor gravida, commodo pellentesque turpis pretium. Maecenas ut libero viverra, dapibus ligula a, aliquam dolor. - $(model.name |> escapeHtml) + + ${model.name |> escape_html} Maecenas interdum diam quis felis posuere ${model.name |> escape_html} blandit. Pellentesque eu arcu est. Cras auctor vitae leo a egestas. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum sed turpis ipsum. Phasellus dictum neque risus, in viverra ante tempor bibendum. Donec vitae odio faucibus, faucibus magna non, consequat enim. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec dignissim mauris dui. Integer nec enim magna. Integer semper felis eu mauris pulvinar facilisis. Vivamus ac augue quam. Aliquam viverra, risus sed vehicula posuere, sapien lorem mattis nibh, eget blandit lorem purus sit amet elit. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Sed egestas neque id tortor gravida, commodo pellentesque turpis pretium. Maecenas ut libero viverra, dapibus ligula a, aliquam dolor. + ${model.name |> escape_html} Cras suscipit ipsum eu lacus blandit, vitae iaculis mi ultricies. In porttitor, nulla vitae imperdiet efficitur, risus lectus sollicitudin massa, sit amet volutpat lectus elit sit amet risus. Ut in dolor ac justo egestas porta non sit amet dui. Integer sollicitudin faucibus eros, et euismod libero convallis laoreet. Mauris faucibus, odio varius faucibus consequat, enim mauris aliquet mi, eget vehicula est odio quis sapien. Nam lobortis urna et neque malesuada porta. Morbi sed dui faucibus sem tincidunt interdum non et orci. Praesent condimentum mi vel tempor blandit. Cras vel libero quis quam posuere volutpat. Vestibulum et mauris nec risus maximus ultricies. Pellentesque viverra hendrerit augue, sed pharetra velit condimentum eget. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; - + Sed fermentum feugiat ex, sit amet molestie ligula dictum vel. Integer at venenatis urna. Maecenas sed pharetra ligula, eu scelerisque magna. Duis ut lobortis mi. Ut porttitor lobortis commodo. Nam mollis metus et quam imperdiet, a eleifend arcu suscipit. Suspendisse est est, dignissim in dui id, blandit mollis nisi. Donec in ultrices massa, vel aliquet tortor. Interdum et malesuada fames ac ante ipsum primis in faucibus. Pellentesque pellentesque sem tempus erat fermentum tristique. Fusce et erat ac odio ultricies lacinia ac sed erat. Vivamus cursus libero et nisl sollicitudin, vel venenatis erat pretium. - + Praesent placerat elementum velit, nec iaculis purus elementum vitae. Integer non fermentum mi. Vestibulum et enim nec felis accumsan sodales. Fusce tincidunt lacus quis tincidunt vestibulum. Nullam vel quam sit amet lacus rhoncus porttitor. Donec eros mauris, vehicula vel ligula eget, commodo volutpat tortor. Maecenas semper felis ac metus tincidunt semper. Nulla facilisi. - + Phasellus ligula mi, tempor vel egestas ac, viverra id magna. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed dolor massa, blandit sed sodales condimentum, suscipit sit amet mi. Duis viverra a felis vel iaculis. Donec cursus nisl sit amet orci dignissim feugiat. Integer et risus tempus, euismod ligula ut, feugiat ante. Aenean placerat rutrum lorem, eget eleifend ligula. Vivamus dapibus lacus a urna lobortis venenatis. In hac habitasse platea dictumst. Mauris a hendrerit nibh. Ut diam enim, blandit sit amet ultrices lobortis, vulputate at quam. Mauris at lectus nec enim fringilla dictum. Pellentesque nulla sapien, efficitur nec tempor at, porta vitae elit. Mauris non laoreet turpis. - + Curabitur ac dolor a arcu vehicula mollis sed vitae nisi. Mauris pulvinar justo vitae diam pharetra, nec tempor quam luctus. Nunc in blandit magna, in malesuada ligula. Sed sed magna cursus, gravida nisl ut, posuere neque. Donec pulvinar interdum porta. Morbi in nibh in augue sagittis lacinia. Duis vel gravida nisi, sed pellentesque tortor. Ut commodo condimentum lacus, eget euismod lectus. Proin sapien nunc, volutpat vitae eleifend vel, lobortis non libero. Mauris hendrerit vel turpis non sagittis. Aliquam euismod, odio eu sodales vehicula, metus ex ultrices tellus, non ultrices libero ipsum sit amet erat. Nam rutrum pretium arcu, a porta ligula gravida non. - + Sed a leo maximus, tristique enim eu, malesuada nibh. Proin scelerisque dui in enim fermentum, molestie cursus nunc rhoncus. Aliquam cursus sollicitudin interdum. Aliquam tempus purus dapibus lorem placerat, sit amet viverra ex sagittis. Nullam fringilla viverra bibendum. Duis viverra ut nunc ac imperdiet. Vivamus mauris nibh, pharetra sed dolor quis, suscipit ultrices dui. Mauris sed accumsan velit. Vivamus accumsan lectus at mauris facilisis, a venenatis lorem posuere. - + Sed vitae eros ullamcorper, pharetra lectus id, malesuada felis. Praesent sit amet est metus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Suspendisse id luctus justo. Aliquam eget facilisis mi. Nunc nec nulla interdum, lobortis mi eget, vehicula quam. Sed quis nisl sed erat egestas mollis. Aliquam a sapien molestie, efficitur nunc id, auctor lacus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Suspendisse ut tellus ac mi consectetur laoreet. Sed consequat congue turpis sit amet eleifend. Nam eu justo tortor. - + Mauris ac elit auctor, maximus orci ut, commodo dolor. Mauris accumsan porttitor condimentum. Nullam faucibus elit nisi, id volutpat lorem sollicitudin sed. Etiam aliquam eros sed leo rutrum pharetra. Ut tristique leo nec arcu pretium, at dapibus sem molestie. Mauris nec fringilla augue. Pellentesque nec dolor porta, varius dui sed, efficitur massa. Donec ut mi at elit elementum suscipit at eu odio. Proin eu scelerisque massa. - + Curabitur justo erat, sagittis vel euismod at, molestie vitae metus. Cras quis condimentum ante. Donec arcu ex, pulvinar vitae consectetur sed, cursus sit amet ante. In leo lacus, mattis vel bibendum ac, volutpat et ex. Morbi at iaculis est. Phasellus interdum a odio sed placerat. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Proin porttitor velit vitae mi rhoncus, a luctus nisi venenatis. Ut et mauris vel lorem cursus ultrices. Fusce dictum nisl at arcu porta, vitae consectetur nisl porttitor. - + Phasellus blandit ultricies porta. Vivamus orci magna, euismod ut molestie eu, aliquet sed erat. Nulla a lorem in neque posuere dignissim. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Duis non ligula vel risus convallis fermentum id ac arcu. Vestibulum feugiat luctus tellus, in sollicitudin lectus consectetur at. Duis tempor, risus ut ultricies pretium, nisi nibh interdum arcu, non dignissim turpis nulla at lectus. Nam non feugiat dolor, eu semper ex. Morbi eu venenatis risus, et lacinia arcu. Donec non dignissim nibh. Integer quam odio, laoreet ac lorem eu, efficitur ultricies dolor. Vivamus laoreet lectus in bibendum rutrum. Nullam porttitor nec est vel maximus. Proin ullamcorper nunc erat. Aliquam ante libero, luctus vitae facilisis non, dignissim nec velit. - + Etiam id nulla diam. Morbi facilisis sit amet libero vel porta. Mauris eget nunc posuere, placerat elit ac, euismod quam. Nam volutpat dolor sit amet lacus feugiat, ut consectetur libero interdum. In molestie magna vitae velit placerat, id finibus massa maximus. Vestibulum cursus tempor felis, vitae placerat magna sollicitudin non. Proin varius mi elit, nec tincidunt lectus lobortis et. Pellentesque fringilla sodales purus, non gravida lectus tempus laoreet. Sed porttitor porta eros, id vehicula massa ornare sed. Aenean laoreet lacinia orci, eget rutrum arcu ultrices sed. Integer vehicula rhoncus tellus aliquet hendrerit. Quisque in congue felis, nec pellentesque diam. - + In finibus velit at diam ornare, sed congue quam pulvinar. Quisque porttitor semper lobortis. Pellentesque rhoncus feugiat mattis. Curabitur lectus lacus, sodales semper eleifend vehicula, rhoncus imperdiet ex. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Etiam pretium condimentum enim, ac tempor enim gravida in. Aliquam ut quam a nisl faucibus cursus ut et ante. Fusce dictum malesuada accumsan. Sed iaculis molestie rutrum. Phasellus malesuada felis vitae faucibus gravida. - + Nam posuere nisl in mi molestie, mattis iaculis leo tincidunt. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Mauris a lorem dignissim, commodo mauris scelerisque, auctor neque. In semper tincidunt quam quis lacinia. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent volutpat leo est, et elementum odio sagittis sed. In ornare a enim a varius. Curabitur consequat metus et orci scelerisque sollicitudin. - + Ut nec orci augue. Sed mauris turpis, convallis mollis tristique eu, faucibus at velit. Praesent egestas sapien vitae mauris finibus, eget interdum erat consequat. Mauris convallis lorem et auctor finibus. Aliquam vehicula facilisis mi, et ultricies dolor consequat quis. Vivamus rhoncus nunc enim, vel laoreet nisi condimentum vitae. Integer sed ullamcorper odio. Pellentesque varius nulla augue, sit amet efficitur orci fringilla non. Vivamus porttitor pellentesque aliquam. Suspendisse suscipit blandit lacus eget imperdiet. Integer at vulputate tortor. Proin purus urna, aliquam ut porta vitae, mollis quis lectus. Proin blandit dignissim tincidunt. Morbi lacinia pharetra nulla et semper. Etiam bibendum odio vitae lacus imperdiet, sed tristique diam imperdiet. - + Nunc tempor sagittis aliquam. Etiam vitae imperdiet sem, sed volutpat massa. Sed rutrum lorem nec commodo tristique. In quis tempor magna. Cras ultricies condimentum sem, sed finibus nisl tempus sed. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Proin rutrum, arcu ac sodales pellentesque, ante augue hendrerit orci, in aliquet ligula nunc vitae est. - + Aenean ut nunc turpis. Aenean sit amet tortor euismod, egestas augue id, tincidunt lectus. Donec ex ex, luctus vel libero quis, volutpat tempor nunc. Morbi semper neque eu urna tempus sodales. Aliquam vel tellus urna. Ut sollicitudin felis neque. Suspendisse sodales ipsum a nunc varius, eu hendrerit lorem viverra. Sed ut vulputate orci. - + Morbi eleifend dictum mollis. Maecenas gravida non libero ut accumsan. Nullam at ante justo. Duis non dolor nisl. Etiam vitae fringilla massa. In pellentesque dolor congue ipsum feugiat auctor. Vestibulum ac ipsum vel leo blandit finibus et et enim. - + Praesent semper hendrerit leo, vel ultricies risus dapibus quis. Donec fringilla egestas hendrerit. Sed diam elit, volutpat in massa ac, iaculis pretium nisl. Suspendisse mi dolor, ullamcorper et erat eu, mollis interdum lorem. Proin malesuada diam a tellus elementum, eu mattis sapien scelerisque. Vestibulum lobortis sed ex et semper. Sed ac varius lorem. Vivamus fermentum eros tellus, sed tincidunt ex laoreet at. Fusce rhoncus scelerisque enim et sagittis. Nullam nec semper quam, a viverra felis. Nulla fringilla ornare nibh rhoncus ullamcorper. - + Curabitur varius, est non vulputate placerat, risus quam tincidunt sem, eu mollis justo lectus sed purus. Proin ornare nisl eu ante pretium, eu finibus metus facilisis. Fusce dapibus aliquam malesuada. Nunc mollis ligula venenatis augue ultrices tincidunt. Sed imperdiet eu magna sed posuere. Donec nec hendrerit velit. Maecenas blandit felis id ante commodo, a sodales enim eleifend. - + Suspendisse in odio in nibh tempor sollicitudin vitae a metus. Curabitur id consectetur purus. Nullam condimentum, ex quis sollicitudin ultrices, dolor turpis interdum ipsum, ut consectetur lorem eros non ligula. Fusce dictum, nisl at aliquam elementum, urna mi congue odio, sed ullamcorper mauris neque sed tortor. Pellentesque risus purus, sagittis eget quam non, dignissim tempor felis. Ut auctor id libero non vulputate. Nam facilisis mattis dolor vel dapibus. Etiam cursus metus id bibendum fringilla. Nulla quis felis faucibus, sollicitudin erat sit amet, sollicitudin purus. - + Donec purus neque, egestas vel vulputate id, porttitor at sem. Aenean et urna lacus. Phasellus ante dui, pretium ac nulla at, dignissim mollis libero. Curabitur fringilla a mi eu rhoncus. Praesent porttitor ipsum id leo laoreet, eget elementum tellus tempor. Donec accumsan volutpat tristique. Aenean dapibus quis dolor vel congue. - + Sed euismod ut nulla nec maximus. Phasellus bibendum odio nibh. Nullam rhoncus, urna at interdum auctor, ex nibh sollicitudin erat, at feugiat felis libero sit amet orci. Nam eu dolor id erat malesuada pellentesque. Etiam hendrerit dolor sit amet posuere rhoncus. Nunc pellentesque mi lorem, pellentesque aliquam neque sagittis laoreet. Nulla eget sagittis neque, sit amet iaculis purus. - + Sed suscipit orci porta eros congue, dictum ornare erat vestibulum. Mauris laoreet tortor tellus, sit amet cursus dolor tincidunt ac. Integer id felis eu erat ornare viverra. Fusce malesuada eros ante, in maximus magna pharetra et. Sed vehicula hendrerit mattis. Sed lectus eros, tincidunt ut consectetur nec, congue id diam. Sed sagittis tempus tincidunt. Etiam at aliquam nibh. Quisque aliquam vitae erat vitae tempor. Fusce ac varius diam. Nunc non rhoncus purus. Etiam gravida ligula in justo congue, vel suscipit augue accumsan. - + Sed placerat sapien ac metus finibus, et feugiat sem tincidunt. Fusce vehicula ac ante ac pretium. Proin molestie consectetur elementum. Suspendisse ultrices velit gravida bibendum scelerisque. Aliquam aliquet vehicula auctor. Aenean gravida lectus at nibh lacinia porta. Vestibulum non dui sit amet lectus cursus bibendum ac interdum lorem. Vestibulum leo eros, ultricies non convallis quis, pharetra at sapien. Nullam eget ipsum sit amet augue feugiat vulputate nec eget nisl. Mauris volutpat orci non erat scelerisque, ut tempus ipsum vestibulum. Morbi lobortis fermentum scelerisque. Aliquam ac est in ante aliquam pharetra. Maecenas vel lectus vel leo maximus suscipit ac id quam. Donec feugiat, urna nec fringilla euismod, neque mauris iaculis urna, vel cursus arcu nulla at felis. Aliquam molestie metus interdum scelerisque fermentum. - + Aenean ultricies neque vitae dui ullamcorper dictum. Cras nec dolor rutrum, accumsan lorem in, tincidunt urna. Aenean vitae congue libero. Sed aliquam ac tortor sit amet mollis. Sed feugiat est vel arcu pharetra dignissim. Duis bibendum blandit metus et posuere. Proin dignissim semper nulla, quis mattis nulla interdum a. Etiam tincidunt maximus lorem at dignissim. Cras convallis nisl eu turpis semper, a dapibus ante maximus. In tincidunt mi ut dignissim dictum. Phasellus hendrerit consequat libero. Vivamus tempor mi in mauris faucibus sollicitudin. Nam a massa efficitur, fringilla ligula sit amet, fringilla felis. Duis blandit justo nec ipsum aliquam volutpat. Aliquam elit nulla, suscipit non viverra id, rhoncus iaculis eros. Quisque volutpat mi eu massa dictum, quis lacinia ligula eleifend. - + Sed blandit eleifend vulputate. Morbi aliquam congue elit, non lacinia felis finibus sed. Vivamus vehicula libero vel ultricies mollis. Nam feugiat tellus ligula, quis porta felis bibendum eu. Vivamus eu elementum purus, vel molestie risus. Fusce cursus, libero pretium iaculis cursus, lacus mi rutrum urna, vel congue turpis arcu ac metus. Vestibulum iaculis pellentesque mi, eu aliquam velit dignissim eu. Sed semper est ac sapien scelerisque pellentesque. Donec lobortis mauris laoreet egestas aliquam. Fusce vulputate nulla ultrices urna gravida, eu tempus nulla viverra. Sed id diam quis ex porttitor maximus. Suspendisse erat dui, posuere vitae ipsum sit amet, rutrum cursus erat. Nulla vel libero ante. Phasellus velit leo, malesuada eu pharetra pellentesque, hendrerit sed nisi. - + Aenean non commodo nulla, non ornare nulla. Donec eleifend dolor nec vestibulum rhoncus. Donec convallis semper posuere. Donec elementum lacus id dui volutpat pharetra. Suspendisse elementum mattis est. Mauris vulputate pretium mi, nec venenatis justo condimentum quis. Curabitur sit amet ante eget dolor sagittis tempus eget nec tellus. Nullam feugiat eleifend justo non iaculis. Suspendisse quis luctus velit. Suspendisse ut dui ac mauris gravida ultricies eget at risus. - + Sed augue nibh, interdum vitae viverra at, hendrerit at justo. Nullam lobortis orci libero, in hendrerit est facilisis non. Quisque sit amet orci sed arcu placerat consectetur. Curabitur hendrerit eros a ex tempor aliquam. Sed sit amet egestas nisl. Ut eget scelerisque elit. Duis id ante massa. Pellentesque in ante in purus gravida lobortis quis eget elit. Proin laoreet sem in auctor congue. Etiam a fermentum enim. Nunc nec maximus lorem. Aliquam interdum convallis libero. Fusce vitae nisl sed urna congue pharetra a non elit. Vestibulum posuere purus in dapibus venenatis. Donec semper nunc eget est tincidunt aliquam. In hac habitasse platea dictumst. - + Ut id tristique urna. Phasellus hendrerit ullamcorper euismod. Vivamus luctus malesuada tempor. Fusce id molestie elit, et elementum justo. Aenean nulla tortor, ullamcorper id tincidunt quis, semper vitae lectus. Maecenas vitae dictum libero. Suspendisse rhoncus lorem quis malesuada laoreet. Praesent finibus ex risus, quis consequat dolor aliquam quis. Nunc magna tortor, aliquet eu nulla vel, ultricies egestas eros. Vivamus varius dictum ipsum, vitae placerat lorem. Praesent luctus augue a ipsum euismod pharetra. Mauris vitae magna vel odio commodo lobortis. Donec et venenatis dolor. - + Integer vitae varius ligula, quis aliquam risus. Fusce ac cursus risus. Vestibulum enim nulla, lacinia sed leo sed, scelerisque ultricies nisi. Etiam vestibulum sapien sit amet ipsum luctus vulputate et interdum odio. Nam diam odio, varius eu convallis sodales, bibendum in mi. Proin convallis consequat odio, vitae blandit enim iaculis eget. Vivamus posuere massa purus, eu accumsan leo sodales ut. Donec imperdiet tincidunt nisl at interdum. Phasellus tempor eget turpis non tempus. Pellentesque volutpat nulla at consectetur ornare. - + Phasellus ac nisi lectus. Etiam magna nisi, tincidunt eu elit eu, imperdiet venenatis metus. Vestibulum non urna ut tortor pulvinar mollis. Nunc fermentum sodales erat, a mollis lectus bibendum vel. Integer a justo in libero dapibus lobortis. Nunc lobortis ex massa, sit amet tristique lacus tristique in. Suspendisse non cursus tellus. Suspendisse vestibulum, nunc in ultricies consequat, justo purus malesuada leo, lacinia dictum lectus diam eget quam. Nullam ut hendrerit tortor. Quisque nec diam eget purus egestas euismod a vel sapien. - + Quisque tristique suscipit justo et blandit. Proin feugiat, ante id congue elementum, ante leo faucibus massa, a accumsan dolor urna in libero. Quisque lacinia leo ut rhoncus vehicula. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse eget lacus posuere, porttitor eros non, imperdiet magna. Nam non pulvinar neque, vitae ultrices dui. Donec eget urna nec velit vestibulum interdum rutrum eu lectus. Aliquam feugiat, sapien a fringilla luctus, magna ipsum scelerisque risus, ut finibus risus sapien a eros. Vestibulum in massa a dui dictum egestas. Nullam vitae viverra felis. Duis maximus, erat quis aliquet dignissim, urna eros consequat nunc, et vehicula sapien enim at leo. Phasellus tempor, lorem sed dapibus condimentum, sapien dui mollis nulla, ut malesuada arcu nunc quis diam. Pellentesque sit amet est et risus lacinia malesuada. Nulla aliquet eu lectus blandit finibus. Vivamus et consequat augue. Etiam pulvinar quam non sagittis tempus. - + Curabitur sed erat ligula. Nulla vitae posuere risus, in tristique ligula. Nam nibh ipsum, venenatis non cursus eget, bibendum eleifend dui. Sed eget luctus dolor. Pellentesque pulvinar tincidunt molestie. Cras varius eros id justo molestie, in dapibus odio elementum. Pellentesque varius, lacus et mollis tincidunt, ante tortor ullamcorper nisi, ac hendrerit turpis odio non enim. Nulla iaculis augue et ipsum varius rutrum. Vestibulum facilisis pulvinar erat id hendrerit. Proin ut lectus convallis, pellentesque orci interdum, bibendum diam. Suspendisse fringilla mauris est. Vivamus feugiat vehicula velit id varius. Etiam in tincidunt eros. Nulla sollicitudin vel odio id sagittis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. - + Duis ut consequat turpis. Sed a venenatis nisl, sit amet dictum dui. Quisque pharetra blandit elit, sollicitudin faucibus elit ultrices sed. Mauris posuere lectus ut ante porta convallis. Sed vulputate neque a rhoncus sollicitudin. Sed in hendrerit nibh. Quisque suscipit dolor eget elit venenatis, eu venenatis purus eleifend. Morbi consequat neque nisi, vitae rhoncus orci dictum non. - + Morbi ut tortor ut tellus ultrices ultrices. Mauris euismod diam in diam pulvinar, ut aliquet risus eleifend. Pellentesque malesuada, erat eu congue hendrerit, justo elit aliquam nisi, eu molestie augue ligula ac lorem. Vivamus fringilla, nisl rutrum fringilla aliquet, mauris dui feugiat ipsum, id tincidunt risus est non dui. Proin tincidunt elit eu vulputate mattis. Vestibulum rutrum at turpis in posuere. In accumsan tincidunt purus. Etiam mollis et diam eget sollicitudin. In ornare venenatis consectetur. Nunc efficitur facilisis nunc cursus ultrices. Aenean purus ligula, feugiat ac laoreet eu, elementum rutrum lacus. - + Nam nec odio molestie, hendrerit sem ac, pulvinar arcu. Ut tristique neque et ipsum cursus tristique. Quisque a mauris ultricies, gravida est quis, aliquet arcu. Nam in urna posuere, rhoncus enim eu, faucibus sapien. Proin aliquet hendrerit dolor egestas maximus. Aenean ligula tellus, luctus vitae pulvinar id, porttitor eu nisi. In consectetur semper ante vitae vestibulum. - + Nunc sodales dictum est eget feugiat. Aenean quis porttitor lectus, ut faucibus lectus. Integer nunc elit, dapibus eget cursus ac, luctus vel nibh. Nunc dapibus molestie placerat. Maecenas facilisis non ante in efficitur. Maecenas ut lectus ac metus pellentesque laoreet eget non augue. Fusce mattis lectus a lobortis lacinia. Integer fringilla sapien tellus, id luctus nisl aliquam quis. Praesent sed consequat nulla, sed tristique nunc. Sed in velit eget neque luctus sollicitudin ultricies eget odio. Mauris tempor aliquam nibh, ullamcorper feugiat elit pellentesque eget. Maecenas pharetra, lacus sed lacinia eleifend, diam leo consequat magna, ac molestie felis ante a leo. Donec consequat pretium urna cursus lobortis. Nunc vestibulum a enim vitae dapibus. Integer ligula sem, egestas placerat euismod sed, aliquet eu eros. - + Duis finibus ex nulla, et gravida purus consequat vitae. Nunc faucibus metus eget justo efficitur varius. Proin ac enim vitae nulla interdum lobortis vel ac metus. Nullam semper, ex malesuada tempor gravida, massa justo auctor mauris, eget tempus risus metus non odio. Maecenas quis tempor enim. Maecenas pulvinar, odio sed tempus hendrerit, enim sapien dictum dolor, non elementum eros ex non odio. Sed nulla diam, consectetur sed efficitur ac, tempus eget ipsum. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Praesent dapibus iaculis ipsum at hendrerit. Integer pharetra odio quis consequat gravida. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Pellentesque fringilla vitae metus id mattis. - + """, if Bool.true then [ """ - - + + """, if Bool.true then [ """ - - + + """, if Bool.true then [ """ - - + + """, if Bool.true then [ """ - - + + """, if Bool.true then """ - + {|list model.cities |} Vivamus pretium sit amet massa sed mollis. Donec ornare elit id risus finibus vestibulum. Praesent felis erat, suscipit quis tellus sit amet, vehicula convallis erat. Interdum et malesuada fames ac ante ipsum primis in faucibus. Maecenas porta est ac tempus ornare. Nunc quis mattis odio. Quisque eu orci condimentum, venenatis nunc a, bibendum dolor. Nam vel pulvinar erat, nec dignissim diam. Sed faucibus mauris ut eleifend consectetur. Nulla facilisi. Donec in scelerisque quam, sit amet viverra ex. Nulla faucibus tincidunt orci, ut viverra nulla laoreet id. Aenean a mollis sapien, suscipit accumsan mauris. Nulla facilisi. Proin in laoreet tellus. Vestibulum et elit justo. - + Integer sodales, ligula non viverra tempor, ipsum mauris porta lacus, nec varius augue orci vel eros. Morbi id purus nisi. Quisque arcu ipsum, vehicula vel ultrices ac, vestibulum vitae nulla. Proin eget vulputate turpis. Donec at dolor in massa rutrum rhoncus. Integer non lectus nec dolor scelerisque tempor ut sit amet erat. Sed gravida eu enim a feugiat. Etiam nunc dolor, suscipit sodales sem eu, venenatis elementum ante. Integer tempor neque sit amet tellus ultricies, ut vulputate neque consequat. - + Vivamus sem ante, viverra nec eleifend suscipit, auctor in libero. Praesent eu lacinia lectus. Ut maximus neque vel sem porta cursus. Vivamus auctor ultricies nibh non sagittis. Morbi dapibus sagittis tortor, vitae euismod massa tempor in. Mauris in diam tristique, congue elit a, cursus ante. Etiam cursus pharetra ante in eleifend. Donec sed porttitor sapien, id condimentum massa. Nulla congue luctus pellentesque. Nullam finibus lectus et quam volutpat vulputate. Suspendisse aliquam eget lacus id bibendum. Sed bibendum tellus in ornare malesuada. {|endlist|} - + """ else "", """ - - - """ + + + """, ] - |> Str.joinWith "" + |> Str.join_with("") else "", """ - - - """ + + + """, ] - |> Str.joinWith "" + |> Str.join_with("") else "", """ - - - """ + + + """, ] - |> Str.joinWith "" + |> Str.join_with("") else "", """ - - - """ + + + """, ] - |> Str.joinWith "" + |> Str.join_with("") else "", """ - + Integer at dui enim. Curabitur sodales, magna vitae mollis dictum, augue massa elementum est, nec sagittis nulla ante ac nisl. Morbi gravida porta metus posuere mollis. Vestibulum porttitor purus a orci vestibulum bibendum. Integer eleifend, eros ac congue tempus, nunc urna sollicitudin eros, quis tempor tortor risus et tellus. Praesent venenatis tincidunt neque, non faucibus massa imperdiet vel. Maecenas pharetra libero eget quam cursus suscipit. Ut malesuada feugiat urna, lobortis sagittis nisl imperdiet quis. Nam dictum justo risus, sed placerat turpis gravida eget. Etiam convallis in sem quis luctus. Aliquam leo dolor, condimentum at massa sit amet, volutpat semper magna. Phasellus urna nisl, viverra vitae ornare in, interdum non arcu. Aliquam mollis orci a vulputate facilisis. Maecenas nulla mauris, cursus in convallis id, dapibus in tellus. - + Donec a felis volutpat, pellentesque arcu et, eleifend mauris. Pellentesque in elit odio. Pellentesque facilisis placerat convallis. Nam mattis sem eget lorem elementum finibus. Quisque congue, nisl a molestie molestie, mauris risus tempus odio, at tempor quam augue id eros. Integer id bibendum nibh, eget faucibus lacus. Aenean hendrerit felis sit amet tincidunt scelerisque. Maecenas suscipit quam ut ultricies pellentesque. Integer sit amet porta lorem. Sed vestibulum, augue sed mollis porta, metus enim maximus odio, eu tempus dui augue vitae ex. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quis odio eget tortor vestibulum venenatis. Nunc metus tellus, efficitur non fermentum quis, porttitor eu quam. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. - + Mauris bibendum, nulla in ullamcorper venenatis, justo orci posuere risus, non ornare odio neque in felis. Aliquam erat volutpat. Ut ultricies arcu diam, ac mollis risus fringilla vitae. Nulla molestie et augue in interdum. Cras urna metus, condimentum a vestibulum id, euismod ut enim. Fusce non nisi et tellus tincidunt convallis sed tristique justo. Sed in maximus urna, id vulputate augue. Phasellus sollicitudin massa non ante molestie pharetra. - + Aenean ac nisl tristique, aliquet ipsum in, euismod eros. Suspendisse ex enim, pharetra quis nisl vel, auctor consectetur tellus. Integer sit amet gravida ex. Sed viverra neque non tristique pharetra. Sed nec augue sed metus laoreet cursus. Morbi mollis ante sed ante molestie pharetra. Vivamus quis turpis convallis, auctor velit id, consectetur lorem. Morbi at elit vel ligula mattis sollicitudin. Morbi non scelerisque ante. - + Ut tempor luctus tellus. Nunc placerat rutrum sapien in vulputate. Donec sagittis ultrices semper. Etiam laoreet tincidunt nulla ac elementum. Morbi ut augue nec tellus interdum pulvinar in non turpis. Nulla tempor tincidunt tristique. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. - + Etiam vehicula nunc vitae quam varius sodales. Phasellus sagittis, arcu quis aliquam ultrices, velit ex dictum diam, nec tristique dolor lacus ut eros. Proin aliquam euismod varius. Fusce eleifend pulvinar sapien, ut accumsan arcu. Pellentesque euismod purus lectus, ut volutpat nunc mollis ut. Sed sagittis eleifend lacus sit amet consequat. In eget ex augue. Quisque consequat lectus scelerisque velit commodo sollicitudin eu feugiat ligula. Nam id imperdiet lorem, facilisis finibus est. Duis volutpat lorem quis felis varius sollicitudin. Aliquam bibendum, eros ac auctor suscipit, orci ipsum feugiat nisl, ut ullamcorper orci augue eget lacus. Sed mollis leo nec auctor venenatis. - + Nam nec maximus ex. Nam et posuere sapien. Nulla posuere dictum lacinia. Nullam sed eleifend lorem. Suspendisse pharetra rhoncus nulla, molestie pulvinar lorem mattis eu. Cras cursus erat ex, ultrices eleifend nulla laoreet nec. Suspendisse nec felis rhoncus, convallis purus in, mattis quam. - + Proin convallis euismod orci, vitae efficitur erat commodo ac. Nunc quis massa vel enim porta cursus a et erat. Praesent tincidunt velit in tempus porta. Ut dignissim luctus enim quis molestie. Aenean nec massa finibus, euismod ipsum id, molestie urna. Nulla scelerisque at tellus in vulputate. Pellentesque tortor odio, tempus sed tristique quis, ultrices nec sapien. Aenean nunc neque, semper tincidunt gravida eu, elementum eu ligula. Donec vehicula nibh lorem, nec sollicitudin ipsum convallis id. Duis ex enim, dictum vitae risus vel, dapibus cursus purus. Vivamus vel sem lacus. Vestibulum luctus, massa id faucibus ornare, est nisi tempus diam, id lacinia magna dui at velit. Interdum et malesuada fames ac ante ipsum primis in faucibus. Mauris tristique lectus ut mi eleifend tincidunt. - + Nam molestie est ut sem venenatis elementum. Suspendisse vel pretium tortor, et feugiat purus. Maecenas porttitor luctus tortor et fringilla. Mauris lobortis, dolor ut scelerisque vulputate, nulla massa facilisis lacus, ac rhoncus ante sem at magna. Sed ultrices iaculis dui et ultricies. Suspendisse et nulla diam. Pellentesque ac malesuada turpis. Sed viverra ultricies turpis, in pharetra turpis scelerisque nec. Sed feugiat ex id tincidunt lacinia. Maecenas rutrum, leo egestas commodo fringilla, nibh nisi tristique nunc, eu porttitor sem metus non augue. In vitae lectus nisl. Cras non fermentum sem. Vivamus a ligula quis lorem finibus ullamcorper id a nunc. Sed eleifend, risus eget cursus molestie, libero magna bibendum enim, non mattis massa elit id velit. - + Donec eu est iaculis, eleifend nunc tempus, molestie arcu. Aliquam porta sodales ultrices. Duis a ex vitae elit pharetra varius. Donec condimentum gravida facilisis. Morbi tristique eros ut augue vehicula, nec tincidunt tortor sollicitudin. Phasellus gravida, felis eu vehicula pharetra, augue diam tristique augue, ac elementum leo est ac sapien. Integer tempor lacus odio, eu efficitur velit porttitor vitae. - + Nullam feugiat semper magna in congue. Etiam porta tincidunt enim, eget blandit magna tempus eget. Sed condimentum finibus quam, posuere sollicitudin leo maximus eleifend. Sed neque erat, dictum ac tincidunt quis, bibendum ut ipsum. Praesent at dolor sagittis, aliquet justo non, eleifend ipsum. Aliquam quam quam, fermentum in mollis nec, convallis eu mi. Pellentesque accumsan porttitor orci a congue. Interdum et malesuada fames ac ante ipsum primis in faucibus. Aenean iaculis feugiat faucibus. - + Donec eget elit est. Sed fermentum tristique ipsum eu consectetur. Sed hendrerit, lorem et ultrices ultrices, ex ante porta turpis, quis interdum magna mi quis eros. Ut convallis elementum ligula, ac gravida metus blandit et. Praesent cursus tempus quam, vitae dapibus felis congue et. Nullam lacinia turpis nec justo porta ornare. Sed volutpat mauris eget dignissim venenatis. Praesent eu elit blandit, sollicitudin tortor eu, tempus urna. Pellentesque diam erat, laoreet et aliquam eget, ullamcorper quis libero. Ut non tempus augue. - + Quisque egestas interdum quam id porttitor. Nulla volutpat, ligula id bibendum blandit, nibh arcu pulvinar ex, id feugiat massa purus sed elit. Proin interdum dui eu augue feugiat, sed auctor eros molestie. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Aenean nec tincidunt ipsum. Sed in odio molestie, facilisis tortor non, posuere ligula. Interdum et malesuada fames ac ante ipsum primis in faucibus. Fusce hendrerit consequat diam vitae luctus. Proin feugiat, est id finibus dictum, est erat dignissim nisi, quis dictum libero odio cursus leo. Sed neque risus, fermentum in urna et, iaculis porta arcu. Nullam tempus magna ac tempor accumsan. - + Integer consectetur ipsum quis tristique scelerisque. Nam eleifend laoreet ligula pharetra volutpat. Phasellus consequat condimentum lacinia. Integer sit amet eleifend elit. Duis non tincidunt mi. Nam augue ex, fringilla blandit risus eu, rhoncus rhoncus tortor. Nullam consequat sagittis gravida. Cras semper non ex vitae sagittis. Ut fermentum ex ligula. Praesent dignissim leo diam, ac pulvinar magna aliquam a. Ut in libero quis nisi molestie cursus ac finibus mi. Mauris leo libero, pulvinar in ipsum a, ornare eleifend mi. - + Integer interdum massa libero, ornare ornare sapien eleifend ut. Nulla at scelerisque purus. Morbi ut velit et ligula rutrum scelerisque nec id neque. Nunc dictum ut odio ac commodo. Donec a augue enim. Donec nibh augue, rhoncus sit amet placerat quis, viverra nec purus. Fusce eget vehicula magna. Praesent nec consectetur lectus, ut commodo ipsum. Praesent placerat in libero eget convallis. Mauris interdum porttitor tortor, maximus porttitor felis accumsan non. Aliquam semper velit ut arcu tempus varius sit amet at elit. - + Mauris dapibus iaculis eros ut ornare. Quisque euismod quam arcu, id dictum nisl tempor sed. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; In at nisi lobortis, mattis dolor vel, pretium ex. Nulla facilisi. Suspendisse potenti. Praesent semper pharetra libero. Nunc sit amet nunc convallis, laoreet est in, convallis neque. Nulla blandit ultrices lacus, vitae sagittis urna. Nam congue mi eu luctus condimentum. - + Sed et dui ullamcorper, euismod libero placerat, suscipit urna. Pellentesque dui erat, lobortis ut aliquam rutrum, sodales eget ex. Vivamus vel est sed leo lobortis elementum ut sit amet orci. Fusce ullamcorper sapien et dui porttitor, id tempus dui placerat. Etiam orci diam, dapibus sed pellentesque sed, rutrum ut massa. Nunc fringilla nulla leo, ut molestie lectus fringilla ac. In elit justo, sagittis a elementum at, pharetra id elit. - + Donec dolor arcu, maximus vel ullamcorper eu, tincidunt a elit. Proin leo velit, vulputate ut odio eu, pharetra congue turpis. Sed a dolor justo. Suspendisse eu dolor sodales mi pellentesque volutpat. Aenean posuere tempus ex, nec luctus ligula dapibus vitae. Morbi nunc quam, pellentesque non dui eget, hendrerit lobortis ante. Nam tempus commodo cursus. Etiam id quam ut urna ullamcorper euismod. Aliquam enim dolor, lacinia at volutpat sed, feugiat at diam. Lorem ipsum dolor sit amet, consectetur adipiscing elit. - + Fusce sit amet lorem ac neque tincidunt porta. Quisque interdum mi ut nulla facilisis tristique. Maecenas lacinia justo sed elit sollicitudin tempus. In consequat felis vitae auctor aliquam. Nulla purus arcu, congue ac scelerisque vitae, dignissim quis odio. Curabitur suscipit, augue ut feugiat egestas, eros leo semper lorem, eget malesuada sem nibh eget ante. Nullam nisi magna, malesuada eget sollicitudin dignissim, ornare in risus. Mauris fermentum quam in arcu sollicitudin tincidunt. Morbi maximus ut mi sed vestibulum. Aliquam pellentesque tempus tempor. Duis sed urna eget nisl mattis blandit quis eget risus. - + Nunc non nulla sit amet enim tempor lacinia a et nibh. Interdum et malesuada fames ac ante ipsum primis in faucibus. In dapibus quis mi in congue. Phasellus in ullamcorper orci, sit amet elementum elit. In non mi bibendum, viverra erat sed, dictum risus. Integer commodo risus ac metus viverra blandit. Nam bibendum augue et leo ultricies mollis. Cras auctor blandit facilisis. Vivamus ut dolor a enim sodales sodales. Nunc sit amet porta eros, faucibus consequat odio. Suspendisse ex diam, sodales in lectus vitae, maximus egestas quam. Duis quis sollicitudin lorem. Ut a sapien lorem. - + Sed vel dolor dui. Aliquam vestibulum ultrices rhoncus. Phasellus volutpat euismod nibh a finibus. Nulla ut mauris eget felis cursus rhoncus tincidunt a ante. Ut interdum, dolor sed lacinia luctus, mi lacus tristique metus, in scelerisque augue nunc non dolor. Suspendisse a augue ut lorem semper ultricies. Vestibulum lacus lorem, lacinia venenatis justo at, imperdiet luctus quam. Aliquam erat volutpat. Sed ligula justo, blandit a feugiat eget, egestas at diam. In nec malesuada libero. - + Sed et blandit purus. Proin arcu massa, pulvinar sed mollis eu, pretium ac lectus. In consequat mi quis egestas sagittis. Cras ut porttitor massa. Morbi ac nisl vitae nibh malesuada mollis. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris sed convallis nibh. Cras laoreet, sapien sit amet imperdiet tristique, tellus est eleifend urna, vitae iaculis mi purus id odio. Curabitur commodo tristique magna, lobortis semper elit ultrices at. Aliquam vehicula pulvinar ipsum, quis congue turpis tempus consectetur. Nunc rhoncus purus ante, ac facilisis ipsum dapibus at. Aliquam hendrerit elit et vestibulum pretium. In hac habitasse platea dictumst. Nullam ultrices auctor nibh, sit amet consectetur est vestibulum pulvinar. - + Donec et dolor eget massa bibendum tempus. Integer ut luctus nisl. Phasellus vel sagittis turpis. Integer placerat sit amet ligula fermentum varius. Vivamus malesuada rhoncus pharetra. Proin purus ante, elementum nec metus aliquet, tincidunt congue nisl. Maecenas in finibus nunc. Proin gravida vitae quam vitae varius. Aenean fermentum, enim eget dapibus aliquet, dolor urna bibendum urna, venenatis lobortis nibh nulla eu risus. Ut gravida tincidunt elit quis ullamcorper. Vivamus hendrerit urna id urna euismod, in venenatis tellus accumsan. Praesent sed sapien sem. Nullam pharetra interdum mauris, scelerisque molestie ante egestas nec. - + Morbi at urna id est pretium aliquet. Integer sed vulputate nunc. Maecenas facilisis nulla lectus, id fringilla ex euismod in. Ut quis sapien orci. Nullam a sem auctor metus feugiat faucibus eget at felis. Ut vel nunc odio. Vestibulum cursus, lacus id sagittis euismod, mauris augue tristique metus, id vestibulum eros lacus sit amet dolor. Proin sollicitudin, quam nec pharetra dapibus, metus orci tincidunt dolor, a consectetur odio urna vel arcu. Donec et consequat mauris, ut luctus eros. - + Aenean id eleifend elit, sed sodales leo. Cras scelerisque blandit lacinia. Sed placerat leo lectus, et auctor lorem laoreet eu. Curabitur eget orci fringilla, ullamcorper felis vitae, pulvinar elit. Curabitur vitae elit quis metus laoreet pharetra. Etiam non quam lacus. Duis a diam ligula. Etiam vel dignissim nunc, sit amet interdum neque. Nullam sit amet mauris arcu. Aenean eu blandit libero, eget gravida diam. Ut nec leo at quam convallis tristique. Cras vitae sem metus. Fusce mauris elit, interdum aliquet enim eget, interdum laoreet quam. Mauris viverra mattis ipsum vel fringilla. Nullam auctor dignissim eleifend. - + Suspendisse faucibus justo in diam interdum, sagittis viverra justo gravida. In feugiat purus at nisi sollicitudin malesuada. Aliquam consectetur bibendum diam, vel maximus ipsum blandit et. Donec eu maximus tortor. Sed malesuada tempor feugiat. Donec eget ex id dui tristique finibus sed eget orci. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nam urna augue, tincidunt quis fringilla sit amet, consequat sit amet arcu. Nunc in libero mauris. Sed ut malesuada ipsum, tempus imperdiet felis. Maecenas tristique purus et pretium varius. - + Nullam varius quis ex non congue. Ut condimentum sem vitae eros congue rhoncus. Quisque sed nunc a velit pulvinar pretium. Donec tempor euismod tellus quis fermentum. Sed in porta mi. Praesent ultricies est non condimentum porttitor. Aliquam sodales, odio quis vestibulum sodales, ligula nisi sagittis risus, ut euismod felis ligula sit amet sem. - + Donec fringilla mi ultrices imperdiet congue. Donec leo augue, dapibus et sem vel, vehicula pharetra lacus. Quisque magna nisi, vehicula ut urna id, porttitor auctor mi. In vestibulum, velit in euismod hendrerit, nisl neque porttitor nisl, sed ultrices metus dolor non metus. Sed velit lectus, consectetur a sem quis, rhoncus sagittis ex. Sed vitae faucibus lacus. Pellentesque lobortis tempor dui. In ipsum diam, iaculis at lobortis id, elementum nec elit. Quisque ante lectus, condimentum non tristique vitae, pharetra at magna. Cras placerat nibh urna, eget elementum dui egestas eget. Nunc euismod, leo sed viverra fringilla, justo libero pulvinar massa, a porttitor tellus mi nec elit. Quisque in vehicula massa, id dapibus nibh. Phasellus non ipsum vitae justo suscipit eleifend at id augue. Pellentesque pellentesque at metus nec facilisis. In ut orci et felis faucibus finibus. Suspendisse aliquam lorem quis maximus viverra. - + Nullam sed egestas orci, id scelerisque velit. Quisque malesuada nunc ut orci tristique mollis ac non leo. Maecenas efficitur venenatis est eu lacinia. Suspendisse in tincidunt libero, tempus commodo mi. Sed id libero congue, rhoncus felis sit amet, eleifend metus. In elementum, justo in faucibus viverra, libero diam bibendum purus, eu vulputate turpis quam vitae massa. Vestibulum posuere sodales tellus, vitae aliquet lectus venenatis sit amet. - + Curabitur sed nunc in tortor vulputate condimentum. Mauris eget venenatis turpis, nec pharetra nulla. Integer quam nisi, condimentum ut aliquet nec, fermentum vel nibh. Fusce congue dui at velit lobortis efficitur. Vestibulum pellentesque enim vitae leo posuere consequat. Vivamus ipsum tellus, feugiat sit amet congue id, varius vel nisi. Integer eu congue lorem. Nam feugiat leo ex, consectetur sollicitudin lorem mollis sed. - + Vivamus sodales, erat quis accumsan fermentum, elit mi aliquet lacus, in lacinia nisi est non justo. Donec ut rhoncus purus. Mauris efficitur neque in nisi luctus, et tincidunt ipsum ultricies. Ut iaculis congue pellentesque. Ut tincidunt, odio eget accumsan dapibus, tellus ex dictum nulla, vitae congue velit quam in ipsum. Sed rutrum consequat eros, sit amet cursus mi eleifend in. Pellentesque risus orci, auctor eu sapien ut, pretium vulputate quam. Suspendisse in dui dignissim lorem tristique vestibulum. Cras vestibulum augue tortor, sed efficitur arcu dapibus sit amet. - + In rhoncus vel ligula in venenatis. Sed non sem sem. Nam vel ante vitae nulla finibus finibus rhoncus at sem. Aenean vulputate maximus vestibulum. Integer id accumsan diam, eget porttitor enim. Vestibulum sollicitudin vel ante in finibus. Nam fringilla interdum felis eu scelerisque. Etiam mi dui, convallis at nibh sed, ullamcorper fermentum velit. Pellentesque ut sagittis sem. - + Phasellus porttitor ut ex vitae congue. Aenean volutpat lectus quam, ac posuere quam tincidunt et. Suspendisse eget odio turpis. Vivamus purus massa, ullamcorper sed congue eu, molestie in magna. Pellentesque nec est tortor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed orci odio, hendrerit eu est in, lacinia imperdiet diam. Integer cursus urna eu lectus egestas malesuada. - + Fusce tincidunt congue dapibus. Morbi eu sem arcu. Praesent a vestibulum massa. Nullam venenatis ac leo eget lobortis. Interdum et malesuada fames ac ante ipsum primis in faucibus. Proin in facilisis eros. In libero nulla, lobortis eget ligula at, ultrices sagittis enim. Vivamus mattis ac purus sit amet pharetra. Donec quis eleifend enim. Pellentesque ante enim, gravida ac placerat eget, varius ac justo. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam ac libero eget leo lobortis pellentesque non ac nunc. Aenean vel ex laoreet, pretium velit facilisis, suscipit dolor. - + Maecenas eleifend ultrices vehicula. Nullam ultricies in eros a facilisis. Morbi cursus diam id nibh lobortis, eu posuere metus vehicula. Vivamus ornare, turpis eu molestie tempor, lorem libero volutpat est, sit amet lacinia neque ex vitae urna. Sed vehicula ultricies quam eget suscipit. Aenean mollis tincidunt mollis. Cras laoreet odio vel ex malesuada porttitor. Nullam ac massa a leo varius malesuada ac ac orci. Donec quis orci non sapien porttitor placerat. Aliquam sagittis, lacus et bibendum suscipit, orci est auctor est, ut vulputate tortor arcu ac orci. Aenean placerat, libero et elementum tristique, dui metus lobortis dui, a consectetur lacus orci id ante. Ut augue diam, feugiat ac efficitur eu, molestie luctus odio. Sed fringilla at eros sit amet efficitur. - + Nullam ac dictum nunc. Quisque at ornare orci. Suspendisse eget urna ipsum. Nam et aliquet leo. Aliquam id hendrerit ligula. Suspendisse bibendum imperdiet leo, id sagittis turpis vehicula sit amet. Donec sit amet posuere massa, sed sodales odio. Nunc placerat velit vitae sodales viverra. Aenean vehicula fringilla malesuada. Integer rutrum odio ac mauris dapibus tempor. Suspendisse tempus vel purus sed faucibus. - + Sed ullamcorper ornare diam vel convallis. Ut et mollis libero. Suspendisse sagittis dapibus luctus. Nam accumsan id turpis vitae feugiat. Interdum et malesuada fames ac ante ipsum primis in faucibus. Aenean non elit libero. Ut eros lectus, ullamcorper non finibus non, blandit ac mauris. Cras pellentesque enim maximus turpis laoreet, feugiat facilisis ex ultricies. Donec auctor gravida velit, eget dignissim orci feugiat quis. Sed faucibus molestie purus quis viverra. Interdum et malesuada fames ac ante ipsum primis in faucibus. Donec suscipit, sem eu ornare dictum, sapien risus imperdiet leo, at convallis ex diam sit amet ligula. Lorem ipsum dolor sit amet, consectetur adipiscing elit. - + In venenatis sodales lacus, ac placerat sem. Donec vitae sollicitudin nisi. Quisque sed lacus non nulla mattis interdum. Phasellus in purus a metus accumsan auctor eget in mi. Nullam id nisl id turpis mattis tempus ac convallis dolor. Suspendisse potenti. Vestibulum finibus lacus orci, at maximus neque scelerisque sed. Aliquam vitae eleifend nisl. Nunc pellentesque velit nisi, ac dapibus nisl dignissim non. Nunc sed turpis non nisl lacinia fermentum. Phasellus quis turpis diam. Maecenas interdum nulla a faucibus ornare. Aenean a tortor ac sem facilisis venenatis. Proin bibendum ut dolor vitae efficitur. Nam maximus mi a tellus pharetra hendrerit. - + Aliquam auctor mi nulla, ut laoreet eros ornare in. Etiam nisl nulla, tristique in rutrum vitae, congue ut ipsum. Suspendisse ipsum mauris, porttitor id ornare sed, tempus et ipsum. Morbi sagittis felis posuere, pretium neque eu, lobortis odio. Donec interdum ut tellus at interdum. Ut ultrices sed turpis ut iaculis. Donec eleifend velit eget vulputate feugiat. Sed et ex massa. Etiam maximus a purus eu aliquet. Duis vel ante nisi. Proin nibh ante, tempor aliquet ornare ac, fermentum dictum quam. In finibus in purus at ultrices. Aenean maximus, diam eget finibus iaculis, mauris mauris pharetra tortor, sed suscipit urna arcu at nisi. Nunc a elit ac ante commodo varius. Etiam imperdiet lorem nec diam tincidunt, posuere cursus odio tincidunt. - + Morbi aliquet et diam a convallis. Sed eu semper est. Nullam dictum pulvinar justo, in mollis nisi posuere ut. Aliquam et volutpat libero, sit amet maximus nisl. Aenean dignissim odio eu massa convallis, eu ultrices mauris sagittis. Morbi finibus purus est, lacinia cursus arcu mattis vel. Nulla condimentum dui id ante tempus aliquam. In pellentesque malesuada egestas. Pellentesque ultricies condimentum aliquet. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque lectus est, aliquam sollicitudin dignissim at, imperdiet in dolor. Vestibulum nisi ex, pharetra et luctus quis, ultricies ultricies odio. Sed tempus consectetur odio, in porttitor nibh maximus ut. Pellentesque ultrices diam et libero malesuada condimentum. Fusce nec nulla in augue vehicula vestibulum. - + Vestibulum bibendum vulputate hendrerit. Vivamus id enim blandit, vestibulum dolor sed, mollis magna. Donec at felis eu augue molestie molestie at id mauris. Mauris ullamcorper sapien pellentesque metus ultrices tristique. Sed egestas, mauris vel congue viverra, quam ante pellentesque ex, sit amet facilisis sapien nibh consectetur augue. Proin lobortis venenatis mi, ac lobortis lorem tincidunt ac. Quisque consectetur sollicitudin rutrum. Nam viverra mi augue, non tincidunt magna imperdiet eu. Aliquam rhoncus ex vitae mauris pharetra, et varius erat fermentum. Curabitur fringilla lobortis sapien, nec pellentesque ex consectetur id. Pellentesque pretium, leo vel bibendum imperdiet, tortor arcu tincidunt nulla, quis facilisis lorem risus tempus augue. Aliquam eu rhoncus risus. Etiam eu risus lacinia, condimentum massa sit amet, egestas tellus. - + Cras rhoncus purus velit, non tempus arcu fermentum non. Fusce volutpat, nunc sit amet fringilla pretium, nunc libero sodales odio, quis aliquet orci dui ut enim. Phasellus hendrerit, leo eu facilisis volutpat, dui erat tincidunt arcu, at commodo enim purus sit amet sapien. Sed hendrerit odio at convallis lobortis. Curabitur a orci vitae velit sodales bibendum vel eget nibh. Quisque lobortis semper tempus. Nam imperdiet velit vel mauris rutrum, euismod tempor nulla bibendum. Nam vestibulum pharetra tortor. - + Duis consectetur tincidunt magna sed pretium. Integer finibus lectus augue, finibus efficitur turpis malesuada id. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Sed viverra metus sapien, vel finibus neque tristique a. Donec sapien magna, molestie ac sapien quis, vulputate tempor tortor. Morbi posuere ornare massa a tempor. Ut ligula ex, efficitur sit amet mi non, dignissim porta tellus. Donec ut enim a nibh ultrices ultricies in non orci. Etiam sed malesuada diam, ac aliquam eros. Curabitur non sodales risus. Praesent placerat arcu diam. Proin consequat sodales mauris, quis tincidunt lectus feugiat sit amet. Integer ultricies nulla orci, venenatis tincidunt ex ornare quis. Curabitur est dolor, maximus ut purus sed, pretium blandit lectus. Integer et porttitor leo. Nullam nibh nisl, lacinia vel ex non, sollicitudin varius odio. - + Nunc sit amet cursus ipsum, ut gravida quam. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur volutpat, est ac placerat lacinia, purus mi egestas tellus, consequat suscipit orci ipsum et eros. Etiam fermentum odio eget diam aliquet, non scelerisque ligula dapibus. Aliquam facilisis a mi vitae blandit. Donec id posuere ipsum. Integer euismod purus at lobortis rutrum. Aliquam vitae tempor sapien, id mattis quam. Praesent id erat quis purus ornare venenatis ac a tortor. - + Suspendisse congue semper enim a convallis. Nullam felis est, mattis sit amet gravida id, ornare in urna. Mauris tellus lorem, rhoncus sit amet ante et, congue volutpat magna. Aliquam eros risus, suscipit egestas aliquam a, tristique at risus. Praesent malesuada pulvinar orci et vulputate. Quisque dictum consequat enim vel hendrerit. Vestibulum arcu augue, consequat quis sollicitudin non, consectetur non lectus. Cras mollis porttitor egestas. Aliquam suscipit malesuada elit, sit amet convallis dui. Sed pellentesque lorem ut odio imperdiet, in porta neque elementum. Ut placerat ante tincidunt leo congue, sit amet viverra neque laoreet. In hac habitasse platea dictumst. - + Aliquam tellus ipsum, gravida in lacus a, sodales ornare nisi. Vestibulum nec ligula eu nunc rhoncus tincidunt ac nec velit. Quisque quis nunc vel nulla aliquet ultrices. In rutrum aliquet ultricies. Nulla tincidunt euismod dolor vel tempus. Etiam ante lectus, lobortis eget odio sit amet, convallis scelerisque odio. Sed pellentesque odio tortor, in elementum leo scelerisque rutrum. - + Ut quis erat ac lacus elementum ornare et ac diam. Phasellus commodo vel nisl at ornare. Donec id venenatis nunc, nec tincidunt augue. Nunc sed leo vel sapien viverra luctus a vel magna. Aenean ac ante a enim sollicitudin maximus a nec sem. Aenean suscipit ullamcorper tellus eget ornare. Praesent gravida tristique orci. Aliquam erat volutpat. Duis condimentum consequat aliquet. Donec condimentum est at odio bibendum posuere. Nam vel lobortis felis, id vestibulum risus. - + Morbi pulvinar vulputate auctor. Donec congue iaculis orci, sit amet rhoncus arcu. Proin porttitor nunc eu nisl ornare fermentum. Donec et risus suscipit, rhoncus elit a, semper arcu. Vestibulum eu nisi quis mi accumsan bibendum. Fusce non pharetra ex. Donec ornare vulputate metus vel ornare. Quisque iaculis sapien eget risus aliquet, a dictum tellus posuere. Fusce sit amet lectus lorem. Aenean vehicula blandit vehicula. Pellentesque lobortis nisi vel quam pulvinar maximus. In in elementum nisl. Sed interdum eros ac cursus elementum. Mauris turpis dolor, aliquet sed molestie nec, facilisis eu felis. Fusce mauris nisi, mollis at lectus vitae, convallis tempor arcu. Vivamus elementum urna diam, eget egestas sapien dignissim eget. - + Nam volutpat, turpis quis aliquet sodales, tortor eros feugiat quam, nec sodales lectus tellus sed mi. Praesent at erat tellus. Morbi fringilla convallis odio, eget aliquet justo tempor id. Fusce semper erat eget diam rhoncus egestas. Nam condimentum ornare nisi non placerat. Pellentesque risus mauris, lobortis sit amet dictum sed, rhoncus efficitur purus. Donec varius scelerisque pretium. Aliquam faucibus nec elit et facilisis. Maecenas lacinia gravida erat in finibus. Cras ipsum est, aliquet vel lacus at, consectetur rutrum ligula. Suspendisse potenti. - + Cras in posuere felis, eu mollis nibh. Vivamus finibus nec ipsum nec finibus. Nulla consectetur posuere nisi, a tincidunt lacus vestibulum in. Suspendisse potenti. Morbi in risus tincidunt, euismod arcu ac, iaculis mi. Vivamus ac pharetra lectus, non iaculis tortor. Vivamus tempus ex fermentum, egestas justo tempor, viverra ex. Morbi venenatis mollis nibh, id tristique odio sollicitudin quis. Aenean quis leo interdum, molestie sapien id, dapibus dolor. Nulla tempor porttitor auctor. Etiam sed auctor quam, ac scelerisque turpis. - + Morbi nec nulla auctor, ultrices lectus et, gravida augue. Etiam et mi risus. Donec euismod convallis turpis a vehicula. Quisque imperdiet, orci auctor sollicitudin fermentum, tellus diam lacinia diam, vitae vulputate sem turpis eu purus. Fusce nec felis sit amet justo mollis euismod. Vestibulum id neque at urna dapibus fringilla in sed mauris. Aliquam cursus fringilla justo, eu venenatis nibh suscipit at. In hac habitasse platea dictumst. - + Interdum et malesuada fames ac ante ipsum primis in faucibus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Suspendisse potenti. Cras dignissim lectus in rhoncus auctor. Mauris quis elit lorem. Etiam rhoncus sapien et lorem molestie molestie. Ut sit amet ullamcorper est. Fusce pretium pretium arcu in accumsan. Cras et ligula sed velit vulputate lacinia. Vivamus nec tincidunt nisi. Vestibulum sed libero ipsum. - + Quisque venenatis commodo orci. Sed sit amet nisl est. Ut placerat, turpis eget mattis porttitor, enim purus pellentesque nibh, in venenatis lorem elit in justo. Maecenas cursus maximus tellus tristique ornare. Pellentesque lacus eros, varius quis tempus sed, fermentum ut purus. Sed elementum aliquam nisl, at aliquam quam convallis non. Fusce consectetur rhoncus turpis sit amet dapibus. Integer dictum ultricies malesuada. Vivamus venenatis purus ut tempus egestas. Maecenas vitae volutpat sem. - + Mauris tincidunt, lorem ut dignissim sodales, nisl justo pretium velit, in luctus quam odio vel nisi. Vestibulum dapibus nibh nulla, eget consequat odio lobortis in. Aenean iaculis est laoreet nulla vehicula suscipit. Ut sit amet ligula posuere, efficitur quam id, elementum arcu. In dapibus ipsum vitae libero vestibulum iaculis. Etiam ante diam, dignissim ac dictum quis, luctus nec nibh. Integer lobortis mollis enim, at porta tortor gravida non. Vestibulum vel arcu a nibh mollis rhoncus id bibendum sem. Nulla facilisi. In volutpat auctor tempor. - + Etiam pretium nisl sed augue pharetra, sed finibus sem porta. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Phasellus non augue posuere, ornare odio eget, hendrerit tortor. Curabitur quis rutrum augue. Donec commodo odio ac enim varius, lacinia lacinia nibh tincidunt. Integer quam sem, condimentum non suscipit vel, egestas vel ante. Etiam scelerisque ante sed elit aliquet congue. Nullam tincidunt ipsum non nisi hendrerit, nec posuere leo rhoncus. Pellentesque blandit mattis elit, ac bibendum ipsum euismod quis. Proin magna mi, placerat in porttitor ac, vulputate quis lorem. Vivamus sit amet eros nisl. Quisque eget posuere magna. Nullam vestibulum id ante id accumsan. Ut a lectus aliquam, iaculis justo ut, dignissim massa. Sed sed turpis efficitur, ornare velit eu, pellentesque ante. Vestibulum venenatis et odio ut eleifend. - + Aenean eget erat malesuada, vulputate neque ac, tristique lorem. Donec scelerisque nibh et ante tristique tincidunt. Proin turpis eros, imperdiet a tincidunt eget, lobortis quis nisi. Nunc in ultricies enim. Suspendisse tincidunt posuere hendrerit. Sed porttitor, neque sed ultricies finibus, quam nisl commodo nulla, in consectetur ex nibh id urna. Fusce nec tellus in ligula consectetur pharetra nec tempus metus. Nunc neque mi, aliquet a dictum ac, fringilla ut sapien. Quisque pharetra consectetur diam. Morbi pretium dolor id elementum ornare. Integer dignissim enim nibh, quis convallis sem vestibulum nec. Maecenas ac lorem a libero bibendum pretium. Nulla vehicula tempor erat non dictum. Donec eu faucibus erat. Quisque pretium tellus id tellus vehicula molestie. - + Donec eu mauris porta, ornare sem at, aliquam mi. Nulla ligula tellus, dapibus sed erat congue, scelerisque consequat massa. Sed eget mollis nisi. Nulla volutpat, tellus accumsan facilisis laoreet, felis dolor luctus est, non accumsan tortor ligula vitae eros. Aenean volutpat maximus dui, quis gravida risus tincidunt quis. Phasellus aliquet lobortis sapien non facilisis. Donec malesuada suscipit dolor et tincidunt. Nunc dui tortor, sollicitudin ut justo faucibus, facilisis ultrices arcu. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Pellentesque rhoncus vehicula lacus, id iaculis nibh feugiat eget. - + Morbi ut nisl a tortor vestibulum hendrerit vitae vitae lorem. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nullam et nisl tempus, condimentum felis at, sollicitudin diam. Nam vitae libero non nunc congue cursus a malesuada nisl. Ut quis hendrerit lorem, at venenatis mi. Vestibulum et velit vitae mauris dictum sodales. Integer vitae ante sed sem vestibulum consectetur. Donec molestie sit amet metus vitae aliquet. Sed rhoncus enim eget magna rutrum mattis. Proin sed diam dapibus, aliquet dui sit amet, consectetur mi. Fusce sollicitudin enim ligula, quis accumsan ex tincidunt et. Maecenas viverra metus elit, sed hendrerit odio sollicitudin quis. - + Quisque porttitor mollis turpis, sed auctor lorem volutpat vel. Morbi eget nulla nec felis eleifend convallis. Nullam mattis lorem eget quam vulputate fringilla. Integer ac sagittis tortor, vel scelerisque neque. Fusce fermentum finibus dolor, eget convallis massa viverra non. Ut fringilla justo vitae nulla mollis, nec auctor enim finibus. Sed odio velit, fringilla nec lorem non, tincidunt semper enim. Donec tellus turpis, viverra quis euismod non, convallis sit amet ante. Nullam sed rutrum ante. In eget massa commodo ex posuere suscipit in in urna. Sed sed sodales massa, ac tincidunt nibh. Donec eu massa vitae nunc luctus interdum et mollis nibh. Nunc volutpat, diam non sodales porta, libero sapien consequat est, nec lacinia dui lorem eu nunc. - + Vestibulum at lacus nunc. Nam ornare nisl lobortis erat iaculis, vel ornare nisi laoreet. Aenean nec pretium eros. Phasellus ultricies ligula eu mauris rutrum egestas. Duis in ligula eu erat fermentum eleifend. Morbi aliquam tellus velit, et tempor diam malesuada eu. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; - + Quisque id ligula id leo feugiat rutrum. Donec bibendum consequat dolor pharetra tincidunt. Vivamus ornare, elit non bibendum eleifend, velit sem mattis nisi, eu hendrerit nisl quam id enim. Nunc nec risus dapibus, posuere nulla sit amet, tempus neque. Aliquam sed egestas sapien. Pellentesque ligula tortor, vulputate a ullamcorper ac, interdum nec felis. Fusce in vehicula risus. Aliquam id pretium ex, et eleifend eros. - + Nullam sed nisl ornare, euismod leo ac, suscipit ex. Etiam tincidunt risus quis molestie mattis. Maecenas ultricies vitae est fringilla accumsan. Aliquam erat volutpat. Aliquam et urna in ex dictum aliquam. Pellentesque ultricies erat quis odio eleifend dapibus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. - + Aenean vitae mauris iaculis, tincidunt erat ut, mollis lectus. Maecenas tincidunt egestas enim vitae auctor. Phasellus et dapibus quam, quis mollis risus. Maecenas consectetur pellentesque massa, sit amet luctus justo venenatis sed. Aliquam interdum accumsan purus ut ultricies. Mauris egestas, purus in laoreet pretium, enim nunc dapibus leo, sed porttitor mi quam rhoncus eros. Aliquam in odio vel mauris pharetra rutrum et et mauris. Quisque nulla massa, faucibus eget finibus in, sollicitudin quis metus. - + Nullam a mi tellus. Maecenas egestas sem ornare erat egestas, et bibendum ligula rutrum. Donec consectetur sapien velit, id ultrices libero ullamcorper non. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Aenean sagittis sollicitudin rhoncus. Donec interdum mollis augue non viverra. Aenean sed lorem mauris. Pellentesque ultrices purus non tortor pulvinar luctus. Quisque condimentum felis enim, id egestas elit rhoncus non. Aenean quis ligula tincidunt, fringilla est feugiat, sollicitudin nulla. Maecenas molestie dolor at nisl pretium cursus. Vestibulum vel efficitur massa. - + Maecenas non orci metus. Praesent efficitur rutrum diam sed dignissim. Duis efficitur vulputate magna at vestibulum. Nam viverra venenatis dui, vel suscipit urna suscipit in. Proin placerat libero eu consectetur congue. Nullam id porttitor orci, vel pharetra lacus. Aliquam at metus eu lorem porta tincidunt. Pellentesque faucibus arcu eget felis iaculis rutrum. Nunc tempus, augue ac lobortis mattis, tortor arcu rhoncus velit, eget malesuada leo est in orci. - + Vestibulum molestie, libero eu volutpat fermentum, lorem magna dignissim lacus, sed ullamcorper magna nunc tincidunt felis. Pellentesque sed rutrum nisi. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nunc consequat faucibus venenatis. Vestibulum pellentesque justo nisi, ornare bibendum diam dictum sed. Integer nec libero eu quam molestie convallis ut a arcu. Duis ullamcorper nisl sit amet enim tempor, aliquam cursus purus malesuada. In bibendum aliquet tellus a blandit. Quisque iaculis, ante consectetur bibendum ullamcorper, ligula massa accumsan erat, a mattis nisi lacus ac nibh. Curabitur in laoreet tortor, quis cursus ex. Proin sit amet elit dictum est aliquam porta. Nulla eget accumsan nisl. Nunc iaculis maximus massa at placerat. Phasellus magna felis, rutrum et rhoncus sit amet, fringilla eget leo. Mauris rutrum enim et lorem volutpat dictum. - + Aliquam finibus venenatis ante, vitae facilisis mauris lacinia ac. In in mollis dui, non venenatis elit. Sed id tempus ipsum. Nunc id eros laoreet, cursus sapien sit amet, mattis tellus. Sed interdum tortor a justo elementum tristique. Nam id semper lorem, vel pharetra est. Morbi porttitor dapibus risus, at commodo tellus egestas eget. In semper leo at lorem mollis dignissim. Donec congue venenatis metus, ac fermentum orci volutpat eget. Nulla vel venenatis purus. Maecenas egestas mattis lorem, a laoreet neque euismod et. Praesent aliquet ut nulla eu semper. Praesent facilisis luctus nibh id venenatis. Integer facilisis eu arcu suscipit facilisis. In faucibus diam nulla, et ornare augue vehicula vel. - + Aliquam vehicula, nisi et placerat ullamcorper, orci urna tempus urna, quis volutpat metus diam interdum sapien. Proin vel eros laoreet, blandit justo sed, hendrerit mauris. Aenean maximus enim lectus, et feugiat velit tincidunt id. Phasellus enim tellus, venenatis eget efficitur ac, venenatis a arcu. Phasellus nec sodales orci. Aliquam ullamcorper volutpat tortor, vel ornare nibh ultricies vel. Duis rhoncus, est at efficitur suscipit, risus nulla fermentum risus, in sollicitudin lectus urna vehicula dui. Pellentesque bibendum, magna id vulputate ultricies, orci nisl tempus dolor, sit amet interdum enim nulla nec erat. Donec vitae lobortis purus. Vestibulum sagittis sollicitudin fringilla. Ut convallis elit ac lacinia varius. Sed eget eros quis enim mollis lobortis vel imperdiet felis. In hac habitasse platea dictumst. Aliquam scelerisque risus leo. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. - + Fusce suscipit dui erat, eu placerat ante sollicitudin quis. Praesent sit amet tortor vitae dui iaculis lobortis ac non lorem. Aenean eget nunc mollis, feugiat turpis facilisis, posuere dolor. Sed pharetra nec lorem sed fermentum. Curabitur eget tincidunt libero. Donec dapibus sollicitudin leo, vitae facilisis augue vestibulum eu. Fusce eu mauris mi. Praesent sollicitudin mi vel luctus euismod. Aenean nec vehicula tortor. Suspendisse molestie non ligula id molestie. Vivamus molestie velit a vehicula condimentum. Mauris venenatis eros semper venenatis gravida. In ut mi malesuada, pulvinar dui ac, aliquet lectus. Integer aliquet metus quis blandit lacinia. Vivamus luctus nibh ac tellus imperdiet lobortis. In feugiat gravida justo sit amet gravida. - - """ + + """, ] - |> Str.joinWith "" + |> Str.join_with("") -escapeHtml : Str -> Str -escapeHtml = \input -> +escape_html : Str -> Str +escape_html = |input| input - |> Str.replaceEach "&" "&" - |> Str.replaceEach "<" "<" - |> Str.replaceEach ">" ">" - |> Str.replaceEach "\"" """ - |> Str.replaceEach "'" "'" \ No newline at end of file + |> Str.replace_each("&", "&") + |> Str.replace_each("<", "<") + |> Str.replace_each(">", ">") + |> Str.replace_each("\"", """) + |> Str.replace_each("'", "'") diff --git a/benchmarks/output.roc b/benchmarks/output.roc index 3ab7e96..f1da7c5 100644 --- a/benchmarks/output.roc +++ b/benchmarks/output.roc @@ -5,10 +5,12 @@ app [main!] { import cli.Stdout import Pages -main! = \_ -> - Pages.lorem { - name: "Benchmark", - color: Red, - items: List.range { start: At 0, end: At 500 }, - } +main! = |_| + Pages.lorem( + { + name: "Benchmark", + color: Red, + items: List.range({ start: At(0), end: At(500) }), + }, + ) |> Stdout.line! diff --git a/examples/basePage/Pages.roc b/examples/basePage/Pages.roc index 96e8d4f..cef53e6 100644 --- a/examples/basePage/Pages.roc +++ b/examples/basePage/Pages.roc @@ -3,18 +3,16 @@ module [ first, base, second, - ] +] - - -first = \model -> +first = |model| """ -

This is the innner content of the page for first. Here's a value: $(model.foo |> escape_html)

+

This is the innner content of the page for first. Here's a value: ${model.foo |> escape_html}

second - + """ -base = \model -> +base = |model| """ @@ -24,25 +22,25 @@ base = \model ->

We want to reuse the outer parts of this page on every page of the website.

- $(model.content) - + ${model.content} + - + """ -second = \model -> +second = |model| """ -

This is a different inner content! Here's another value: $(Num.toStr model.bar |> escape_html)

+

This is a different inner content! Here's another value: ${Num.to_str(model.bar) |> escape_html}

first """ escape_html : Str -> Str -escape_html = \input -> +escape_html = |input| input - |> Str.replaceEach "&" "&" - |> Str.replaceEach "<" "<" - |> Str.replaceEach ">" ">" - |> Str.replaceEach "\"" """ - |> Str.replaceEach "'" "'" \ No newline at end of file + |> Str.replace_each("&", "&") + |> Str.replace_each("<", "<") + |> Str.replace_each(">", ">") + |> Str.replace_each("\"", """) + |> Str.replace_each("'", "'") diff --git a/examples/basePage/server.roc b/examples/basePage/server.roc index a34acad..59817a3 100644 --- a/examples/basePage/server.roc +++ b/examples/basePage/server.roc @@ -4,29 +4,39 @@ import Pages Model : {} -init! = \{} -> Ok {} +init! = |{}| Ok({}) -respond! = \req, _ -> - when Str.splitOn req.uri "/" |> List.dropFirst 1 is +respond! = |req, _| + when Str.split_on(req.uri, "/") |> List.drop_first(1) is ["first"] -> - Pages.base { - content: Pages.first { - foo: "very nice string", + Pages.base( + { + content: Pages.first( + { + foo: "very nice string", + }, + ), }, - } + ) |> success ["second"] | _ -> - Pages.base { - content: Pages.second { - bar: 100, + Pages.base( + { + content: Pages.second( + { + bar: 100, + }, + ), }, - } + ) |> success -success = \body -> - Ok { - status: 200, - headers: [{ name: "Content-Type", value: "text/html" }], - body: body |> Str.toUtf8, - } +success = |body| + Ok( + { + status: 200, + headers: [{ name: "Content-Type", value: "text/html" }], + body: body |> Str.to_utf8, + }, + ) diff --git a/examples/blog/Format.roc b/examples/blog/Format.roc index 1d4ccb6..cc4ce76 100644 --- a/examples/blog/Format.roc +++ b/examples/blog/Format.roc @@ -1,12 +1,14 @@ -module [toUpper] +module [to_upper] -toUpper : Str -> Result Str _ -toUpper = \input -> +to_upper : Str -> Result Str _ +to_upper = |input| input - |> Str.toUtf8 - |> List.map \byte -> - if 'a' <= byte && byte <= 'z' then - byte - 'a' + 'A' - else - byte - |> Str.fromUtf8 + |> Str.to_utf8 + |> List.map( + |byte| + if 'a' <= byte and byte <= 'z' then + byte - 'a' + 'A' + else + byte, + ) + |> Str.from_utf8 diff --git a/examples/blog/Pages.roc b/examples/blog/Pages.roc index 6f01093..086757e 100644 --- a/examples/blog/Pages.roc +++ b/examples/blog/Pages.roc @@ -1,12 +1,12 @@ ## Generated by RTL https://github.com/isaacvando/rtl module [ home, - blogPost, - ] + blog_post, +] import Format -home = \model -> +home = |model| [ """ @@ -21,91 +21,94 @@ home = \model -> - - """ + + """, ] - |> Str.joinWith "" + |> Str.join_with("") -blogPost = \model -> +blog_post = |model| [ """ - + - $(model.post.title |> Format.toUpper |> Result.withDefault "" |> escape_html) - + ${model.post.title |> Format.to_upper |> Result.with_default("") |> escape_html} - Roc Template Example
-

$(model.post.title |> escape_html)

+

${model.post.title |> escape_html}

""", - List.map model.post.content \item -> - [ - """ - - """, - when item is - Text t -> - """ - -

$(t |> escape_html)

- - """ - Code c -> - """ - -
$(c |> escape_html)
- - """ - Image i -> - """ - - - """ - , - """ - - """ - ] - |> Str.joinWith "" - |> Str.joinWith "", + List.map( + model.post.content, + |item| + [ + " ", + when item is + Text(t) -> + """ + +

${t |> escape_html}

+ + """ + + Code(c) -> + """ + +
${c |> escape_html}
+ + """ + + Image(i) -> + """ + + + """, + " ", + ] + |> Str.join_with(""), + ) + |> Str.join_with(""), """ - +
Home
- - """ + + """, ] - |> Str.joinWith "" + |> Str.join_with("") escape_html : Str -> Str -escape_html = \input -> +escape_html = |input| input - |> Str.replaceEach "&" "&" - |> Str.replaceEach "<" "<" - |> Str.replaceEach ">" ">" - |> Str.replaceEach "\"" """ - |> Str.replaceEach "'" "'" \ No newline at end of file + |> Str.replace_each("&", "&") + |> Str.replace_each("<", "<") + |> Str.replace_each(">", ">") + |> Str.replace_each("\"", """) + |> Str.replace_each("'", "'") diff --git a/examples/blog/server.roc b/examples/blog/server.roc index b34ca53..7e126aa 100644 --- a/examples/blog/server.roc +++ b/examples/blog/server.roc @@ -4,44 +4,51 @@ import Pages Model : {} -init! = \{} -> Ok {} +init! = |{}| Ok({}) -respond! = \req, _ -> - when Str.splitOn req.uri "/" |> List.dropFirst 1 is +respond! = |req, _| + when Str.split_on(req.uri, "/") |> List.drop_first(1) is ["posts", slug] -> post = - List.findFirst posts \p -> - p.slug == slug + List.find_first( + posts, + |p| + p.slug == slug, + ) |> try - Pages.blogPost { - post, - } + Pages.blog_post( + { + post, + }, + ) |> success [""] | _ -> - Pages.home { posts } |> success + Pages.home({ posts }) |> success posts = [ { title: "How to write a template engine in Roc", slug: "template-engine", - content: [Text "Roc's type inference shines through here. It makes it easy to write a template language with compile time errors while having the same feel as dynamic languages."], + content: [Text("Roc's type inference shines through here. It makes it easy to write a template language with compile time errors while having the same feel as dynamic languages.")], }, { title: "My story: thinking of blog ideas for this example", slug: "my-story", - content: [Text "What follows is a code block:", Code "[1,2,3] |> List.map \\x -> x * x"], + content: [Text("What follows is a code block:"), Code("[1,2,3] |> List.map \\x -> x * x")], }, { title: "The last blog post", slug: "fin", - content: [Text "Here's an image", Image "https://www.roc-lang.org/favicon.svg"], + content: [Text("Here's an image"), Image("https://www.roc-lang.org/favicon.svg")], }, ] -success = \body -> - Ok { - status: 200, - headers: [{ name: "Content-Type", value: "text/html" }], - body: body |> Str.toUtf8, - } +success = |body| + Ok( + { + status: 200, + headers: [{ name: "Content-Type", value: "text/html" }], + body: body |> Str.to_utf8, + }, + ) diff --git a/rtl.roc b/rtl.roc index e7c4a5c..5558355 100644 --- a/rtl.roc +++ b/rtl.roc @@ -1,6 +1,6 @@ app [main!] { - cli: platform "https://github.com/roc-lang/basic-cli/releases/download/0.18.0/0APbwVN1_p1mJ96tXjaoiUCr8NBGamr8G8Ac_DrXR-o.tar.br", - weaver: "https://github.com/smores56/weaver/releases/download/0.5.1/nqyqbOkpECWgDUMbY-rG9ug883TVbOimHZFHek-bQeI.tar.br", + cli: platform "https://github.com/roc-lang/basic-cli/releases/download/0.19.0/bi5zubJ-_Hva9vxxPq4kNx4WHX6oFs8OP6Ad0tCYlrY.tar.br", + weaver: "https://github.com/smores56/weaver/releases/download/0.6.0/4GmRnyE7EFjzv6dDpebJoWWwXV285OMt4ntHIc6qvmY.tar.br", } import cli.Stdout @@ -17,157 +17,169 @@ import weaver.Opt import weaver.Cli main! : List Arg => Result {} [Exit I32 Str]_ -main! = \args -> +main! = |args| - start = Utc.now! {} + start = Utc.now!({}) - cli_parser : Cli.CliParser { input_dir : _, output_dir : _, extensionWithoutDot : _ } + cli_parser : Cli.CliParser { input_dir : _, output_dir : _, extension_without_dot : _ } cli_parser = { Cli.weave <- - input_dir: Opt.str { short: "i", long: "input-directory", help: "The directory containing the templates to be compiled. Defaults to the current directory.", default: Value "." }, - output_dir: Opt.str { short: "o", long: "output-directory", help: "The directory Pages.roc will be written to. Defaults to the current directory.", default: Value "." }, - extensionWithoutDot: Opt.str { short: "e", long: "extension", help: "The extension of the template files the CLI will search for. Defaults to `rtl`.", default: Value "rtl" }, - } - |> Cli.finish { - name: "rtl", - version: "0.2.0", - authors: ["Isaac Van Doren "], - description: - """ - Welcome to Roc Template Language (RTL)! - - In a directory containing template files, run `rtl` to generate Pages.roc. Then import Pages to use your templates. - - Get the latest version at https://github.com/isaacvando/rtl. - """, + input_dir: Opt.str({ short: "i", long: "input-directory", help: "The directory containing the templates to be compiled. Defaults to the current directory.", default: Value(".") }), + output_dir: Opt.str({ short: "o", long: "output-directory", help: "The directory Pages.roc will be written to. Defaults to the current directory.", default: Value(".") }), + extension_without_dot: Opt.str({ short: "e", long: "extension", help: "The extension of the template files the CLI will search for. Defaults to `rtl`.", default: Value("rtl") }), } + |> Cli.finish( + { + name: "rtl", + version: "0.2.0", + authors: ["Isaac Van Doren "], + description: + """ + Welcome to Roc Template Language (RTL)! + + In a directory containing template files, run `rtl` to generate Pages.roc. Then import Pages to use your templates. + + Get the latest version at https://github.com/isaacvando/rtl. + """, + }, + ) |> Cli.assert_valid - when Cli.parse_or_display_message cli_parser args Arg.to_os_raw is - Err msg -> Stdout.line! msg - Ok parsedArgs -> generate! parsedArgs start + when Cli.parse_or_display_message(cli_parser, args, Arg.to_os_raw) is + Err(msg) -> Stdout.line!(msg) + Ok(parsed_args) -> generate!(parsed_args, start) -generate! : { input_dir : Str, output_dir : Str, extensionWithoutDot : Str }, Utc => Result {} _ -generate! = \{ input_dir, output_dir, extensionWithoutDot }, start -> - extension = extensionWithoutDot |> Str.withPrefix "." - info! "Searching for templates in $(input_dir) with extension $(extension)" |> try +generate! : { input_dir : Str, output_dir : Str, extension_without_dot : Str }, Utc => Result {} _ +generate! = |{ input_dir, output_dir, extension_without_dot }, start| + extension = extension_without_dot |> Str.with_prefix(".") + info!("Searching for templates in ${input_dir} with extension ${extension}") |> try paths = - Dir.list! input_dir - |> Result.map \ps -> - keep_templates ps extension - |> Result.mapErr \e -> error "Could not list directories: $(Inspect.toStr e)" - |> try + Result.map_ok( + Dir.list!(input_dir), + |ps| + keep_templates(ps, extension), + ) + ? |e| error("Could not list directories: ${Inspect.to_str(e)}") invalid_template_names = - List.map paths \p -> - get_file_name p - |> Str.replaceLast extension "" - |> List.dropIf is_valid_function_name - - if !(List.isEmpty invalid_template_names) then - error + List.map( + paths, + |p| + get_file_name(p) + |> Str.replace_last(extension, ""), + ) + |> List.drop_if(is_valid_function_name) + + if !(List.is_empty(invalid_template_names)) then + error( """ - The following templates have invalid names: $(invalid_template_names |> Str.joinWith ", ") + The following templates have invalid names: ${invalid_template_names |> Str.join_with(", ")} Each template must start with a lowercase letter and only contain letters and numbers. - """ + """, + ) |> Err + else + templates = + map_try!( + paths, + |path| + File.read_utf8!(path) + |> Result.map_ok(|template| { path, template }) + |> Result.map_err(|e| error("Could not read the templates: ${Inspect.to_str(e)}")), + ) + |> try + + if List.is_empty(templates) then + info!("No templates found") else + # If the directory already exists, Dir.create_all! will return an error. This is fine, so we continue anyway. + _ = Dir.create_all!(output_dir) - templates = - map_try! paths \path -> - File.read_utf8! path - |> Result.map \template -> { path, template } - |> Result.mapErr \e -> error "Could not read the templates: $(Inspect.toStr e)" - |> try - - if List.isEmpty templates then - info! "No templates found" - else - - # If the directory already exists, Dir.create_all! will return an error. This is fine, so we continue anyway. - _ = Dir.create_all! output_dir - - file_path = "$(output_dir)/Pages.roc" - info! "Compiling templates" |> try - File.write_utf8! (compile templates extension) file_path - |> Result.mapErr \e -> error "Could not write file: $(Inspect.toStr e)" - |> try - time = Utc.delta_as_millis start (Utc.now! {}) |> Num.toStr - info! "Generated $(file_path) in $(time)ms" |> try + file_path = "${output_dir}/Pages.roc" + info!("Compiling templates") |> try + File.write_utf8!(compile(templates, extension), file_path) + |> Result.map_err(|e| error("Could not write file: ${Inspect.to_str(e)}")) + |> try + time = Utc.delta_as_millis(start, Utc.now!({})) |> Num.to_str + info!("Generated ${file_path} in ${time}ms") |> try - roc_check! file_path + roc_check!(file_path) roc_check! : Str => Result {} _ -roc_check! = \file_path -> - info! "Running `roc check` on $(file_path)" |> try +roc_check! = |file_path| + info!("Running `roc check` on ${file_path}") |> try - Cmd.new "roc" - |> Cmd.args ["check", file_path] + Cmd.new("roc") + |> Cmd.args(["check", file_path]) |> Cmd.status! - |> Result.onErr \CmdStatusErr err -> - when err is - ExitCode code -> Err (Exit code "") - _ -> Err (Exit 1 "") - |> Result.map \_ -> {} + |> Result.on_err( + |CmdStatusErr(err)| + when err is + ExitCode(code) -> Err(Exit(code, "")) + _ -> Err(Exit(1, "")), + ) + |> Result.map_ok(|_| {}) keep_templates : List Path, Str -> List Str -keep_templates = \paths, extension -> +keep_templates = |paths, extension| paths - |> List.map Path.display - |> List.keepIf \str -> Str.endsWith str extension + |> List.map(Path.display) + |> List.keep_if(|str| Str.ends_with(str, extension)) compile : List { path : Str, template : Str }, Str -> Str -compile = \templates, extension -> +compile = |templates, extension| templates - |> List.map \{ path, template } -> - name = - get_file_name path - |> Str.replaceLast extension "" - { name, nodes: Parser.parse template } + |> List.map( + |{ path, template }| + name = + get_file_name(path) + |> Str.replace_last(extension, "") + { name, nodes: Parser.parse(template) }, + ) |> CodeGen.generate get_file_name : Str -> Str -get_file_name = \path -> - when Str.splitOn path "/" is +get_file_name = |path| + when Str.split_on(path, "/") is [.., filename] -> filename - _ -> crash "This is a bug! This case should not happen." + _ -> crash("This is a bug! This case should not happen.") is_valid_function_name : Str -> Bool -is_valid_function_name = \str -> - bytes = Str.toUtf8 str +is_valid_function_name = |str| + bytes = Str.to_utf8(str) when bytes is - [first, .. as rest] if 97 <= first && first <= 122 -> - List.all rest isAlphaNumeric + [first, .. as rest] if 97 <= first and first <= 122 -> + List.all(rest, is_alpha_numeric) _ -> Bool.false -expect is_valid_function_name "fooBar" -expect is_valid_function_name "a" -expect is_valid_function_name "abc123" -expect is_valid_function_name "123four" |> Bool.not -expect is_valid_function_name "snake_case" |> Bool.not -expect is_valid_function_name "punctuation!" |> Bool.not +expect is_valid_function_name("fooBar") +expect is_valid_function_name("a") +expect is_valid_function_name("abc123") +expect is_valid_function_name("123four") |> Bool.not +expect is_valid_function_name("snake_case") |> Bool.not +expect is_valid_function_name("punctuation!") |> Bool.not -isAlphaNumeric : U8 -> Bool -isAlphaNumeric = \c -> - (48 <= c && c <= 57) - || (65 <= c && c <= 90) - || (97 <= c && c <= 122) +is_alpha_numeric : U8 -> Bool +is_alpha_numeric = |c| + (48 <= c and c <= 57) + or (65 <= c and c <= 90) + or (97 <= c and c <= 122) info! : Str => Result {} _ -info! = \msg -> - Stdout.line! "\u(001b)[34mINFO:\u(001b)[0m $(msg)" +info! = |msg| + Stdout.line!("\u(001b)[34mINFO:\u(001b)[0m ${msg}") error : Str -> [Exit (Num *) Str] -error = \msg -> - Exit 1 "\u(001b)[31mERROR:\u(001b)[0m $(msg)" +error = |msg| + Exit(1, "\u(001b)[31mERROR:\u(001b)[0m ${msg}") map_try! : List input, (input => Result output error) => Result (List output) error -map_try! = \list, func! -> - help! = \remaining, output -> +map_try! = |list, func!| + help! = |remaining, output| when remaining is - [] -> Ok output + [] -> Ok(output) [first, .. as rest] -> - result = try func! first - help! rest (List.append output result) - help! list [] + result = try(func!, first) + help!(rest, List.append(output, result)) + help!(list, []) diff --git a/snapshots/ExpectedPages.roc b/snapshots/ExpectedPages.roc index 0ef480c..6fc7de8 100644 --- a/snapshots/ExpectedPages.roc +++ b/snapshots/ExpectedPages.roc @@ -1,16 +1,16 @@ ## Generated by RTL https://github.com/isaacvando/rtl module [ template, - ] +] import Math -template = \model -> +template = |model| [ """ - + @@ -22,84 +22,88 @@ template = \model ->
    """, - List.map model.items \item -> - """ - -
  1. $(item |> escape_html)
  2. - - """ - |> Str.joinWith "", + List.map( + model.items, + |item| + """ + +
  3. ${item |> escape_html}
  4. + + """, + ) + |> Str.join_with(""), """ - +
- + """, if model.condition then """ - + True """ else """ - + False """, """ - - + + """, - if !model.condition || Bool.false then + if !model.condition or Bool.false then """ - - $(Inspect.toStr model.condition |> escape_html) + + ${Inspect.to_str(model.condition) |> escape_html} """ else "", """ - - -

Module calculation: $(Math.add 123 345 |> Num.toStr |> escape_html)

- + + +

Module calculation: ${Math.add(123, 345) |> Num.to_str |> escape_html}

+ """, when model.animal is - Dog "fido" -> + Dog("fido") -> """ Hello Fido """ - Cat {name: "Gob", age} -> + + Cat({ name: "Gob", age }) -> """ - Hello Gob, Age: $(Num.toStr age |> escape_html) + Hello Gob, Age: ${Num.to_str(age) |> escape_html} """ + _ -> """ Sorry, don't know that animal - """ - , + """, """ - - - $("

Raw interpolation test

") + + + ${"

Raw interpolation test

"} - - """ + + """, ] - |> Str.joinWith "" + |> Str.join_with("") escape_html : Str -> Str -escape_html = \input -> +escape_html = |input| input - |> Str.replaceEach "&" "&" - |> Str.replaceEach "<" "<" - |> Str.replaceEach ">" ">" - |> Str.replaceEach "\"" """ - |> Str.replaceEach "'" "'" \ No newline at end of file + |> Str.replace_each("&", "&") + |> Str.replace_each("<", "<") + |> Str.replace_each(">", ">") + |> Str.replace_each("\"", """) + |> Str.replace_each("'", "'") diff --git a/snapshots/Math.roc b/snapshots/Math.roc index 21185a9..d0d24c0 100644 --- a/snapshots/Math.roc +++ b/snapshots/Math.roc @@ -1,4 +1,4 @@ module [add] -add = \x, y -> +add = |x, y| x + y diff --git a/snapshots/output.roc b/snapshots/output.roc index bfbefbf..3142da6 100755 --- a/snapshots/output.roc +++ b/snapshots/output.roc @@ -5,10 +5,12 @@ app [main!] { import cli.Stdout import Pages -main! = \_ -> - Pages.template { - items: ["first", "second", "third", "fourth", "fifth"], - condition: Bool.true, - animal: Cat { name: "Gob", age: 10 }, - } +main! = |_| + Pages.template( + { + items: ["first", "second", "third", "fourth", "fifth"], + condition: Bool.true, + animal: Cat({ name: "Gob", age: 10 }), + }, + ) |> Stdout.line! From 6ef1589066c65f0ff674610e84fe022ff4853344 Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Fri, 24 Jan 2025 16:13:39 +1100 Subject: [PATCH 2/3] change valid_filename to snake_case, builtins renamed --- CodeGen.roc | 14 +++++++------- rtl.roc | 21 +++++++++++---------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/CodeGen.roc b/CodeGen.roc index 1bc952f..57bd9d6 100644 --- a/CodeGen.roc +++ b/CodeGen.roc @@ -78,11 +78,11 @@ escape_html = escape_html : Str -> Str escape_html = \\input -> input - |> Str.replaceEach "&" "&" - |> Str.replaceEach "<" "<" - |> Str.replaceEach ">" ">" - |> Str.replaceEach "\\"" """ - |> Str.replaceEach "'" "'" + |> Str.replace_each "&" "&" + |> Str.replace_each "<" "<" + |> Str.replace_each ">" ">" + |> Str.replace_each "\\"" """ + |> Str.replace_each "'" "'" """ RenderNode : [ @@ -116,7 +116,7 @@ render_nodes = |nodes| [ ${list} ] - |> Str.joinWith "" + |> Str.join_with "" """ |> indent @@ -142,7 +142,7 @@ to_str = |node| """ List.map ${list} \\${item} -> ${render_nodes(body)} - |> Str.joinWith "" + |> Str.join_with "" """ WhenIs({ expression, cases }) -> diff --git a/rtl.roc b/rtl.roc index 5558355..e2a219e 100644 --- a/rtl.roc +++ b/rtl.roc @@ -149,22 +149,23 @@ is_valid_function_name = |str| bytes = Str.to_utf8(str) when bytes is [first, .. as rest] if 97 <= first and first <= 122 -> - List.all(rest, is_alpha_numeric) + List.all(rest, is_snake_case_char) _ -> Bool.false -expect is_valid_function_name("fooBar") +expect is_valid_function_name("foo_bar") expect is_valid_function_name("a") -expect is_valid_function_name("abc123") -expect is_valid_function_name("123four") |> Bool.not -expect is_valid_function_name("snake_case") |> Bool.not +expect is_valid_function_name("abc_123") +expect is_valid_function_name("123_four") |> Bool.not +expect is_valid_function_name("fooBar") |> Bool.not expect is_valid_function_name("punctuation!") |> Bool.not -is_alpha_numeric : U8 -> Bool -is_alpha_numeric = |c| - (48 <= c and c <= 57) - or (65 <= c and c <= 90) - or (97 <= c and c <= 122) +is_snake_case_char : U8 -> Bool +is_snake_case_char = |c| + (48 <= c and c <= 57) # numbers + or (97 <= c and c <= 122) # lowercase letters + or c + == 95 # underscore info! : Str => Result {} _ info! = |msg| From 97c802151db462eea0f8c2a452dad23ba53b5a2d Mon Sep 17 00:00:00 2001 From: Isaac Van Doren <69181572+isaacvando@users.noreply.github.com> Date: Fri, 31 Jan 2025 22:55:51 -0600 Subject: [PATCH 3/3] more updates --- benchmarks/output.roc | 2 +- examples/basePage/second.rtl | 4 +- examples/basePage/server.roc | 2 +- examples/blog/server.roc | 2 +- rtl.roc | 2 +- snapshots/ExpectedPages.roc | 84 +++++++++++++++++------------------- snapshots/output.roc | 2 +- snapshots/template.rtl | 6 +-- 8 files changed, 50 insertions(+), 54 deletions(-) diff --git a/benchmarks/output.roc b/benchmarks/output.roc index f1da7c5..04b75ec 100644 --- a/benchmarks/output.roc +++ b/benchmarks/output.roc @@ -1,5 +1,5 @@ app [main!] { - cli: platform "https://github.com/roc-lang/basic-cli/releases/download/0.18.0/0APbwVN1_p1mJ96tXjaoiUCr8NBGamr8G8Ac_DrXR-o.tar.br", + cli: platform "https://github.com/roc-lang/basic-cli/releases/download/0.19.0/Hj-J_zxz7V9YurCSTFcFdu6cQJie4guzsPMUi5kBYUk.tar.br", } import cli.Stdout diff --git a/examples/basePage/second.rtl b/examples/basePage/second.rtl index 34e4489..3c8f7d3 100644 --- a/examples/basePage/second.rtl +++ b/examples/basePage/second.rtl @@ -1,2 +1,2 @@ -

This is a different inner content! Here's another value: {{ Num.toStr model.bar }}

-first \ No newline at end of file +

This is a different inner content! Here's another value: {{ Num.to_str model.bar }}

+first diff --git a/examples/basePage/server.roc b/examples/basePage/server.roc index 59817a3..9277ec7 100644 --- a/examples/basePage/server.roc +++ b/examples/basePage/server.roc @@ -1,4 +1,4 @@ -app [Model, respond!, init!] { pf: platform "https://github.com/roc-lang/basic-webserver/releases/download/0.11.0/yWHkcVUt_WydE1VswxKFmKFM5Tlu9uMn6ctPVYaas7I.tar.br" } +app [Model, respond!, init!] { pf: platform "https://github.com/roc-lang/basic-webserver/releases/download/0.12.0/Q4h_In-sz1BqAvlpmCsBHhEJnn_YvfRRMiNACB_fBbk.tar.br" } import Pages diff --git a/examples/blog/server.roc b/examples/blog/server.roc index 7e126aa..f179068 100644 --- a/examples/blog/server.roc +++ b/examples/blog/server.roc @@ -1,4 +1,4 @@ -app [Model, respond!, init!] { pf: platform "https://github.com/roc-lang/basic-webserver/releases/download/0.11.0/yWHkcVUt_WydE1VswxKFmKFM5Tlu9uMn6ctPVYaas7I.tar.br" } +app [Model, respond!, init!] { pf: platform "https://github.com/roc-lang/basic-webserver/releases/download/0.12.0/Q4h_In-sz1BqAvlpmCsBHhEJnn_YvfRRMiNACB_fBbk.tar.br" } import Pages diff --git a/rtl.roc b/rtl.roc index e2a219e..985bcab 100644 --- a/rtl.roc +++ b/rtl.roc @@ -1,5 +1,5 @@ app [main!] { - cli: platform "https://github.com/roc-lang/basic-cli/releases/download/0.19.0/bi5zubJ-_Hva9vxxPq4kNx4WHX6oFs8OP6Ad0tCYlrY.tar.br", + cli: platform "https://github.com/roc-lang/basic-cli/releases/download/0.19.0/Hj-J_zxz7V9YurCSTFcFdu6cQJie4guzsPMUi5kBYUk.tar.br", weaver: "https://github.com/smores56/weaver/releases/download/0.6.0/4GmRnyE7EFjzv6dDpebJoWWwXV285OMt4ntHIc6qvmY.tar.br", } diff --git a/snapshots/ExpectedPages.roc b/snapshots/ExpectedPages.roc index 6fc7de8..90256ed 100644 --- a/snapshots/ExpectedPages.roc +++ b/snapshots/ExpectedPages.roc @@ -1,16 +1,16 @@ ## Generated by RTL https://github.com/isaacvando/rtl module [ template, -] + ] import Math -template = |model| +template = \model -> [ """ - + @@ -22,88 +22,84 @@ template = |model|
    """, - List.map( - model.items, - |item| - """ - -
  1. ${item |> escape_html}
  2. - - """, - ) - |> Str.join_with(""), + List.map model.items \item -> + """ + +
  3. $(item |> escape_html)
  4. + + """ + |> Str.join_with "", """ - +
- + """, if model.condition then """ - + True """ else """ - + False """, """ - - + + """, - if !model.condition or Bool.false then + if !model.condition || Bool.false then """ - - ${Inspect.to_str(model.condition) |> escape_html} + + $(Inspect.to_str model.condition |> escape_html) """ else "", """ - - -

Module calculation: ${Math.add(123, 345) |> Num.to_str |> escape_html}

- + + +

Module calculation: $(Math.add 123 345 |> Num.to_str |> escape_html)

+ """, when model.animal is - Dog("fido") -> + Dog "fido" -> """ Hello Fido """ - - Cat({ name: "Gob", age }) -> + Cat {name: "Gob", age} -> """ - Hello Gob, Age: ${Num.to_str(age) |> escape_html} + Hello Gob, Age: $(Num.to_str age |> escape_html) """ - _ -> """ Sorry, don't know that animal - """, + """ + , """ - - - ${"

Raw interpolation test

"} + + + $("

Raw interpolation test

") - - """, + + """ ] - |> Str.join_with("") + |> Str.join_with "" escape_html : Str -> Str -escape_html = |input| +escape_html = \input -> input - |> Str.replace_each("&", "&") - |> Str.replace_each("<", "<") - |> Str.replace_each(">", ">") - |> Str.replace_each("\"", """) - |> Str.replace_each("'", "'") + |> Str.replace_each "&" "&" + |> Str.replace_each "<" "<" + |> Str.replace_each ">" ">" + |> Str.replace_each "\"" """ + |> Str.replace_each "'" "'" \ No newline at end of file diff --git a/snapshots/output.roc b/snapshots/output.roc index 3142da6..f4802a4 100755 --- a/snapshots/output.roc +++ b/snapshots/output.roc @@ -1,5 +1,5 @@ app [main!] { - cli: platform "https://github.com/roc-lang/basic-cli/releases/download/0.18.0/0APbwVN1_p1mJ96tXjaoiUCr8NBGamr8G8Ac_DrXR-o.tar.br", + cli: platform "https://github.com/roc-lang/basic-cli/releases/download/0.19.0/Hj-J_zxz7V9YurCSTFcFdu6cQJie4guzsPMUi5kBYUk.tar.br", } import cli.Stdout diff --git a/snapshots/template.rtl b/snapshots/template.rtl index 5c354bf..10db817 100644 --- a/snapshots/template.rtl +++ b/snapshots/template.rtl @@ -22,14 +22,14 @@ {|endif|} {|if !model.condition || Bool.false |} - {{Inspect.toStr model.condition}} + {{Inspect.to_str model.condition}} {|endif|} -

Module calculation: {{ Math.add 123 345 |> Num.toStr }}

+

Module calculation: {{ Math.add 123 345 |> Num.to_str }}

{|when model.animal |} {|is Dog "fido" |} Hello Fido - {|is Cat {name: "Gob", age} |} Hello Gob, Age: {{ Num.toStr age }} + {|is Cat {name: "Gob", age} |} Hello Gob, Age: {{ Num.to_str age }} {|is _ |} Sorry, don't know that animal {|endwhen|}