@@ -1,17 +1,698 @@
2−title = "Udon"
2+title = "Sail and Udon"
4template = "doc.html"
4template = "doc.html"
7+Sail is Hoon markup that’s used to render a web page with XML. But what makes it special is that you can run arbitrary Hoon code within such a web page without using a separate markup language.
9+Udon is a way to write content for the web. It's a minimalist markup language for creating and rendering text documents, with a Markdown-inspired syntax. It's integrated with our Hoon programming language, allowing it to be used as standalone prose in its own file or embedded inside a Hoon source file, in which case it will be parsed into a tree of HTML nodes using Sail.
11+This document will be divided into two main sections: the Sail guide and the Udon guide. The Udon guide has two sub-sections that each walk you through a practical example. Also, you're encouraged to read the Getting Started section below, which applies to both Udon and Sail.
6## Table of Contents
13## Table of Contents
15+- #### [Sail: A Guide](#sail)
8−- #### [Udon: A Guide](#guide)
17+- #### [Udon: A Guide](#udon)
19+- #### [Udon: A Simple Blog](#blog)
21+- #### [Udon: A Static Site](#static)
25+Before starting with either Sail or Udon, make sure that your ship is
26+[mounted to Unix](https://urbit.org/docs/using/setup/)
28+To host that output, your ship also has a web-server, called
29+[Eyre](https://urbit.org/docs/using/web/), that can be found at
30+`http://localhost:8080/` if it’s your first ship that’s running on the a
31+machine, `http://localhost:8081/` if it’s the second ship on that same machine,
32+and so on. In the startup messages, a ship will tell you which HTTP port it's
35+The `/web` directory of the `%home` desk is served by default. You can change
36+which desk you're serving by using the command `|serve` in the Dojo. If you
37+have already created and mounted a desk named `%sandbox`, for example, you can
38+switch to serving it with this command:
44+The first time you serve a desk, `/web` will be included as default. After that,
45+you will need to explicitly append `/web` to the desk you're switching to --
46+otherwise, you'll need to write `http://localhost:8080/web` every time you
47+navigate to your web-server. Newly served desks not automatically having `/web`
48+as their root directory is a bug.
50+To switch back to your `%home` desk and set `/web` as your root directory, run:
56+We'll be serving the `%home` desk for the examples in this tutorial.
60+That server has access to source files located in `/<your-urbit>/home/web` and
61+any sub-folders thereof. For the purposes of this tutorial, we will only be
62+using files that are located in the `/<your-urbit>/home/web/pages` path.
64+There is an important distinction between these two paths. According to
65+`/ren/urb.hoon`, any file inside of `/web` or any of its sub-directories
66+is put through a tree of renderers specified at `/ren/urb/tree.hoon`
67+-- _except_ for files inside of `/web/pages`. All of the files in `/web` and
68+its non-`/pages` children directories have various operations on files, such as
69+wrapping your Sail the `html`, `head`, and `body` nodes. This rendering tool,
70+called simply **Tree**, also adds certain formatting polish, such as a sidebar
71+that lists sibling files in the same directory.
73+The `/web/pages` sub-directory is a unique case with its own rendering rules.
74+The Tree is not used when rendering files in this path. The existence of no tag
75+is inferred, and no special formatting is applied. Such simplicity is ideal for
76+introducing the basics of Sail. Any source file located in `/web/pages` must
77+produce a complete HTML node with "head" and "body" nodes as children.
79+Understanding the details of the rendering pipeline is not necessary to complete
80+this tutorial. But, if you are curious, you might find it illuminating to
81+explore the contents of the `/ren` directory.
83+So, if a Sail source file named `sailtest.hoon` is saved in your `/web/pages`
84+folder on your only running urbit process, you can view that source rendered
85+into a web-page at `localhost:8080/pages/sailtest/`.
87+## <a name="sail"></a>Sail: A Guide
89+It’s easy to see how Sail can directly translate to HTML:
96+ ;title: My first webpage
103+ ;script@"http://unsafely.tracking.you/cookiemonster.js";
113+ <title>My first webpage</title>
120+ <script src="http://unsafely.tracking.you/cookiemonster.js"></script>
125+Save the above Sail code in `/home/web/pages/firstsail.hoon`, and the above
126+HTML code in `/home/web/pages/firsth.html`. Access the resulting pages by
127+navigating to `http://localhost:8080/pages/firstsail` and
128+`http://localhost:8080/pages/firsth.html`, respectively, in your browser. The
129+resulting pages should be identical!
131+It shouldn't be hard to see the similarities here. So let's go into more
132+detail about what the differences are.
136+In Sail, tag heads are written with the tag name prepended by `;`. Unlike in
137+HTML, there are different ways on closing tags, depending on the needs of the
138+tag. One of the nice things about Hoon is that you don’t have to be constantly
139+closing expressions; Sail inherits this convenience.
143+Empty tags are closed with a `;` following the tag. Example:
157+Filled tags are closed via line-break. To fill text inside, add `:` after the
158+tag name, then insert your plain text following a space. Example:
172+To nest tags, simply create a new line. Nested tags need to be closed
173+with `==`, because they expect a list of sub-tags. If we nest a line of plain
174+text with no tag, a `<p>` is prepended.
176+Sail, like Hoon, is white-space sensitive. Unlike in Hoon, however, two spaces
177+(called a "gap") is not necessarily equivalent to a line-break in Sail.
182+ This is some good content.
191+ <p>This is some good content.</p>
196+Conversely, if we want to write a string with no tag at all, then we can prepend
197+those untagged lines with `;`.
220+Attributes are key-value pairs that go into an HTML node.
222+Adding attributes is simple: just add the desired attribute between parentheses,
223+right after the tag name without a space. We separate different attributes of
224+the same node by using `,`.
226+Attributes can be used in two forms: flat, which uses one line; and tall, which
227+uses multiple lines, when a single line would not be practical. Flat forms and
228+flat forms are two syntaxes of semantically equivalent expressions.
233+The code below produces a “Submit” button on the page.
238+;input(type "submit", value "Submit");
253+<input type="submit" value="Submit">`
265+<nav id="header">Menu</nav>
268+Add `#` after tag name to add an ID.
272+`;h1.text-blue: Title` equals `<h1 class="text-blue">Title</h1>`
274+Add `.` after tag name to add a class. However, if you want a class name that
275+contains a space, you will need to use use the syntax of a generic attribute:
277+`;div(class "logo inverse");` equals `<div class="logo inverse"></div>`
282+`;img@"example.png";`
286+`<img src="example.png"/>`
288+Add `@` after the tag name to link your source.
290+To add attributes to the image, like size specifications, add the
291+desired attribute after the `"` of the image name and before the final `;` of
296+`;img@"https://urbit.org/example.png"(width "100%");`
300+`;a/"urbit.org": A link to Urbit.org`
304+`<a href="urbit.org">A link to Urbit.org</a>`
306+Add `/` after tag name to start an href.
310+Our first example is useful to understand how Sail syntax translates to HTML
311+syntax, but Sail finds its usefulness in the fact that it can be used seamlessly
314+One place where Sail diverges from HTML is that it supports string
315+interpolation. In Sail, the contents of all tags are a string type called `tape`
316+unless otherwise designated. Tapes are delineated by the double quotes `""`.
317+That’s important, because tapes can be interpolated with Hoon expressions,
318+provided that those expressions produce something a tape as well. Interpolation
319+is done by wrapping the code to be inserted in `{}`. In your Dojo prompt, try
320+the command below (without the `>`):
323+> "I am a l{(mul 3 11)}t Urbit user."
327+Oh no! That command produced a nest-fail error, which indicates that there was
328+a problem related to Hoon type-system. We used the proper `{}` syntax for
329+interpolation, and we used the proper function-call syntax inside of it. So
332+Trying the `mul` function on its own will help answer this question. Try the
333+following command in your Dojo:
340+This should work, producing `33`, an atom. That’s our problem. The
341+interpolation expression expects a tape, but our first command tried to
342+interpolate with something that results in an atom. Try this now:
349+We get a similar result, but we know that it’s a tape because it’s wrapped in
350+`""`. Bingo! With this knowledge, let’s perform a successful interpolation:
353+> "I am a l{<(mul 3 11)>}t Urbit user."
354+"I am a l33t Urbit user."
361+The default subject of a Sail file is different from the subject that
362+expressions in the Dojo or a Hoon generator are evaluated against.
364+To see this difference, first save the code below to a file at
365+`home/web/pages/sub.hoon` and view the rendering at
366+`http://localhost:8080/pages/sub`.
377+Then enter the following command in the Dojo:
383+You'll notice that the Sail subject is like a stripped-down version of the Dojo
384+subject. Its final line should match the Dojo subject.
386+Now swap the code below into your Sail file.
10−- #### [A Simple Udon Blog](#blog)
398+You'll find that the resulting Sail subject is much larger. If you look closely,
399+you'll see that there's some new similarities with the Dojo subject, such as
400+containing the name of your ship. There's also some new differences, since
401+`fuel:html` contains things that are specifically useful for performing
402+web-related operations.
404+### A More Interesting Example
406+Now let’s apply knowledge of string interpolation and the Sail subject in a Sail
407+source file. The following code produces more interesting things than the
408+example we saw before.
413+=+ wid=(met 3 p.bem.gas)
415+?: (lte wid 1) "galaxy"
417+?: (lte wid 4) "planet"
418+?: (lte wid 8) "moon"
422+ ;meta(charset "utf-8");
423+ ;title: A more advanced page
426+ ;h1: This is the Title
428+ ;a/"http://urbit.org": link to Urbit.org.
429+ ;span: Check it out!
432+ ;li(style "color: green"): We're doing interesting stuff now.
433+ ;li: We're pretty-printing this sum with Hoon: {<(add 50 50)>}.
434+ ;li: The code above is shorthand for {(scow %ud (add 50 50))}.
435+ ;li: I am {(trip '~lodleb-ritrul')}.
436+ ;li: Actually, my name is {<p.bem.gas>}. I'm a {what-kind}.
438+ ;div: My name is {<p.bem.gas>}. I'm a {what-kind}.
443+Save the above Sail code in to `home/web/pages/secondsail.hoon` and access the
444+resulting page by navigating to `http://localhost:8080/pages/secondsail` in
447+There are some interesting things here. Let’s go through this code piece by
454+Later in this code we want produce the name of the ship is hosting it, something
455+that looks like ~lodleb-ritrul. In a generator, we could produce our ship name
456+by writing `our` -- try it in the Dojo. But remember that Sail is rendered
457+against its own subject, `our` is not part of the default subject. To augment
458+our subject with the information that we need, we use `/= gas /$ fuel:html`.
460+The above expression uses two Ford runes, `/=` and `/$`, to add the relevant
461+information to the current subject. We can pull the ship’s name out of this
462+augmented subject later. It's important to note that these runes are not part of
463+Hoon. They are part of Ford, our build system.
465+`/$` is used to get data from the environment, and `/=` adds that data to
466+subject in the face `gas`. The
467+[Ford user manual](https://urbit.org/docs/arvo/internals/ford/runes/) has
468+details on these and other Ford runes, but understanding these runes isn’t
469+necessary for the purposes of this tutorial.
471+`fuel:html` gets extra data from your ship’s Eyre module, which handles all
472+things HTTP, and sticks it in the subject when Eyre renders a page. This
473+includes the name of the ship, which is what we look for in the next line, but
474+it includes much more.
476+`p.bem.gas` is an expression that looks for `p` within `bem` within `gas`, the
477+face that we stored the above `fuel:html` expression in. That wing happens to
478+resolve to the name of the ship that is hosting the web-server. If we wanted to
479+access the current desk, we would use the wing expression `q.bem.gas`.
481+You can take a look at what you can access by typing `fuel:html` in the Dojo,
482+and then explore it by modifying your wing expression in your Sail file
489+The above line of code stores a variable used later for a conditional. `&` means
490+`true`, meaning that any evaluation of `show-list` will be true until changed in
494+=+ wid=(met 3 p.bem.gas)
496+ ?: (lte wid 1) "galaxy"
498+ ?: (lte wid 4) "planet"
499+ ?: (lte wid 8) "moon"
503+This code chunk is a series of conditionals that checks the host ship’s name to
504+see what its value is.
506+The first line, `=+ wid=(met 3 p.bem.gas)`, combines a new noun with the
507+subject and gives it the face `wid`. This noun is produced by the the
508+standard-library function [`met`](/docs/reference/library/2c), which measures the number of
509+[blocks](/docs/reference/library/1c/) of size `a` within `b`. Blocks are units that have a
510+bitwidth of `2^a`. So, in this case, it measures how many bytes (blocks of size
511+3 are bitwidths of 8; `2^3 = 8`) are fully contained in your ship's address.
513+Galaxies contain zero to one 3-blocks; stars contain two 3-blocks; planets
514+contain three to four 3-blocks; moons contain five to eight 3-blocks; comets
515+contain nine to sixteen 3-blocks. Each test uses `lte`, the
516+less-than-or-equal-to function, to determine if `wid` is of a given size. The
517+result of this series of tests is added to the subject and given the face
520+Ship names are simply another representation of atoms, and ship
521+categories are different ranges of possible atomic values. Because of this, we
522+perform less-than tests to see what kind of ship is running the web-server.
527+ ;meta(charset "utf-8");
528+ ;title: A more advanced page
532+Sail proper begins here. These four lines are four nodes. The `;html` node
533+indicates that the contained code should be rendered as HTML; this tag is closed
534+on the final line. The `;head` node contains metadata, and is closed three lines
535+later. The `;meta` node sets the character set to UTF-8, and the `;title` node
536+sets the title of the page that shows up in the browser tab.
540+ ;h1: This is the Title
542+ ;a/"http://urbit.org": link to Urbit.org.
543+ ;span: Check it out!
12−- #### [A Static Site](#static)
546+The first line here opens, of course, the body node. The second line creates
549+The third, fourth, and fifth lines of code here construct a single line with an
551+`; This is a` begins the rendered line with plain text.
553+`;a/"http://urbit.org": link to Urbit.org.` continues that same rendered line,
554+and creates hyperlinked text out of `link to Urbit.org.`
556+`;span: Check it out!` continues that same rendered line further. `;span:`
557+has the same use as `<span>` in HTML, and by following it with just a `:` and no
558+attributes, it continues the line without formatting. Following `;span:` with
559+**two** spaces causes there to be single space following the produced `<span>`
560+element, because one of those spaces is syntactically necessary.
562+In the following lines, we beginning to use some Hoon expressions again.
569+In the top line in the chunk above, we use the `;+` Sail rune, which
570+resolves an expression to a single node. That expression, in this case, is
571+`?:`, which tests the truth value of `show-list`, which we assigned the value
572+`&` (meaning “true”) at the beginning of the program. It’s closed by the `==` on
575+Thus, this program resolves to the first child of `show-list`, the node `;ol`.
576+That node creates an ordered list, and the items contained within that node.
579+ ;li(style "color: green"): We're doing more interesting stuff now.
582+The line above is the only element of this list that does not use
583+Hoon proper. The line renders as green, as interpreted by the browser,
584+because of the Sail attribute.
586+The next items in the list use `{}`. Recall that these braces, pronounced “lob”
587+and “rob” in Hoon-speak, allow for the interpolation of code within a string.
590+ ;li: We're pretty-printing this sum with Hoon: {<(add 50 50)>}.
593+The line above is interpolated with Hoon code that produces the sum of 50 plus
594+50, which is wrapped in `<>` to put the product in double quotes to make it a
595+tape, like the rest of the line.
599+ ;li: The code above is shorthand for {(scow %ud (add 50 50))}.
602+The `{(scow %ud (add 50 50)}` on this line is just a different way
603+writing the `{<(add 50 50)>}` expression. `scow` is a Hoon function that turns a
604+noun into a `tape`, Hoon’s string type. `%ud` tells `scow` that its argument
605+should be displayed in the form of an unsigned decimal.
609+ ;li: I am {(trip '~lodleb-ritrul')}.
612+`trip` is a function that takes a `cord` and produces a `tape`. A piece of
613+data of the cord type is one big atom formed from adjacent unicode bytes and
614+delineated by `''`. Remember that all text rendered in Sail is treated as a
615+tape. So, by converting `~lodleb-ritrul` to a tape, it can be included in the
616+tape that we are trying to insert it into without getting a type error.
619+ ;li: Actually, my name is {<p.bem.gas>}. I'm a {what-kind}.
623+The line above has interpolated code that uses a wing expression to access the
624+name of the host ship, and then accesses the face `what-kind` contains a string
625+describing what type of ship it is. We declared `gas` on the very first line so
626+that we could add that sort of information to the subject that our Sail is
627+rendered against. The wing expression `p.bem.gas` looks for `p` within `bem`
628+within `gas`, which happens to be where the name of the ship is located.
630+Note that `{what-kind}` does not have a `<>` wrapper. Why do you think this is?
633+ ;div; My name is {<p.bem.gas>}. I'm a {ship}.
638+The `;div;` node above is only rendered, as an alternative to the above list,
639+if `show-list` is evaluated as true. This means it won’t be shown with your
640+default code. To show this line, change the `&` on line 2 to `|` (“false”).
644+In the previous example, we used a few special runes that aren’t used in typical
645+Hoon code. But there are others that are worth learning about at this point.
647+`;+` is an expression that resolves to a single node. We saw this on line 20
648+in our Sail example above: `;+ ?: show-list` resolves to the node `;ol` and
649+all of that node’s children.
651+`;*` is an expression that resolves to a list of nodes. If we want to render
652+multiple nodes side-by-side, and not just the children of a single node, this
653+is the expression that we use.
655+`;=` turns a tuple of nodes into a list of nodes.
658+To see how these runes work, let’s take a chunk of our previous code starting at
659+line 20 and modify it a bit:
664+ ;li: I am {(trip '~lodleb-ritrul')}.
665+ ;li: Actually, my name is {<p.bem.gas>}.
668+ ;div: My name is {<p.bem.gas>}. I'm a {what-kind}.
674+We changed the conditional branches so that each contains two Sail nodes,
675+side-by-side -- notice that the `;ol` is absent from the first branch.
677+We begin with the `;*` rune, which resolves to a list of nodes, instead of the
678+`;+` rune, which only resolves to a single node.
680+But that’s not enough on its own. `;*` needs to resolve to a list, and a few
681+Sail nodes aren’t lists until they are explicitly made into lists. Until we wrap
682+those nodes in `;=`, the nodes treated as mere tuples. All branches must be
683+valid lists for the `;* ?: show-list` expression to resolve.
687+You should now have foundational knowledge for making web pages with Sail. There
688+is, of course, more to learn.
690+The [Ford manual](https://urbit.org/docs/arvo/internals/ford/runes/)
691+can show you how to access various ship resources for user in your pages. To
692+learn more about how the renderer works, take a look at the
693+`/home/ren/urb.hoon` file inside your urbit.
14−## A Guide
695+## <a name="udon"></a>Udon: A Guide
16Udon is a way to write content for the web. It's a minimalist
697Udon is a way to write content for the web. It's a minimalist
17markup language for creating and rendering text documents, with a
698markup language for creating and rendering text documents, with a
@@ -34,36 +715,7 @@ Markdown: some syntax errors will prevent the file from being parsed at all.
34We provide a few simple examples [here](#examples) of how to publish
715We provide a few simple examples [here](#examples) of how to publish
35Udon files using our web interface.
716Udon files using our web interface.
39−Before starting, make sure that your urbit is
40−[mounted to Unix](https://urbit.org/docs/using/setup/)
42−To host Udon and other kinds of files, your ship also has a
43−web-server, called [Eyre](https://urbit.org/docs/using/web/), that can be found
44−at `http://localhost:8080/` if it’s your first ship that’s running on the
45−machine, `http://localhost:8081/` if it’s the second ship on that same machine,
46−and so on. If you can't find your ship on one of these for some reason, try the
47−next one. When a ship starts, it will print a message like
48−`http: live (insecure, public) on 8081` to let you know what port it's using.
50−That server has access to source files located in `/<your-urbit>/home/web` and
51−any sub-folders thereof (except for `/home/web/pages`, which has special
52−rendering rules.) Your ship's `%home` desk is served by default. You can
53−[change](https://urbit.org/docs/using/web/) which desk you're serving, however.
55−Everything in the `/<your-urbit>/home/web/` directory, with the exception of
56−`/home/web/pages`, knows how to interpret and files of `.udon` type. So, to
57−experiment with UM, create a `.udon` file in that path, and then try to access it
58−at `http://localhost:8080/<yourfile>` in your browser -- no `.udon` required in
59−the URL. It's a good idea to copy-paste the following examples into your file to
60−see how the code works.
62−Make sure that you have proper syntax throughout, and check often that it
63−renders properly as you add more code. If you have parser-breaking syntax, then
64−the default renderer won't tell you much.
66−## Syntax
718+## Udon Syntax
68### Front Matter
720### Front Matter
@@ -129,7 +781,7 @@ through `<h6>`. The header for this section is `### Headers`.
130##### Header (h5)
782##### Header (h5)
132−###### Produces:
784+**Produces:**
134#### Header (h4)
786#### Header (h4)
@@ -150,7 +802,7 @@ element.
150To get their *attention*, you need that _je ne sais quoi_.
802To get their *attention*, you need that _je ne sais quoi_.
153−###### Produces:
805+**Produces:**
155To get their **attention**, you need that _je ne sais quoi_.
807To get their **attention**, you need that _je ne sais quoi_.
@@ -170,7 +822,7 @@ This second line is separated by two newlines, so it's a separate paragraph.
170This line looks like a distinct paragraph, but...
822This line looks like a distinct paragraph, but...
171It's only separated by a single newline, so it's included in the same paragraph.
823It's only separated by a single newline, so it's included in the same paragraph.
173−###### Produces:
825+**Produces:**
176Here's the first line.
828Here's the first line.
@@ -192,7 +844,7 @@ I wonder how long each line
192will be if I put backslashes\
844will be if I put backslashes\
193at the ends of the lines.
845at the ends of the lines.
195−###### Produces:
847+**Produces:**
197I wonder how long each line
849I wonder how long each line
198will be if I put backslashes\
850will be if I put backslashes\
@@ -210,7 +862,7 @@ Here is some *bold* text.
210Here is some \*not bold* text.
862Here is some \*not bold* text.
213−###### Produces:
865+**Produces:**
215Here is some **bold** text.
867Here is some **bold** text.
216Here is some \*not bold* text.
868Here is some \*not bold* text.
@@ -318,7 +970,7 @@ destination.
318[I'm an inline-style link](https://www.urbit.org/docs/reference/shell)
970[I'm an inline-style link](https://www.urbit.org/docs/reference/shell)
321−###### Produces:
973+**Produces:**
323[I'm an inline-style link](https://www.urbit.org/docs/reference/shell)
975[I'm an inline-style link](https://www.urbit.org/docs/reference/shell)
@@ -332,7 +984,7 @@ the all of the URL that the destination has in common with the origin page.
332[I'm a reference-style link](../shell)
984[I'm a reference-style link](../shell)
335−###### Produces:
987+**Produces:**
337[I'm a reference-style link](../shell)
989[I'm a reference-style link](../shell)
@@ -349,7 +1001,7 @@ so we need to use some [Sail](#sail). If there are two or more anchors with
349the same `id` on the page, you will arrive at the earliest instance of the the
1001the same `id` on the page, you will arrive at the earliest instance of the the
352−###### Example:
1004+**Example:**
355Check out this [section](#the-destination) that we want to jump to.
1007Check out this [section](#the-destination) that we want to jump to.
@@ -361,7 +1013,7 @@ It was the best of times, it was the worst of times...
361## Here we are!
1013## Here we are!
364−###### Produces
1016+**Produces:**
366Check out this [section](#the-destination) that we want to jump to.
1018Check out this [section](#the-destination) that we want to jump to.
@@ -381,7 +1033,7 @@ opening and closing quotes -- that is, `“` and `”`.
381"Yes," he said. "That is the way with him."
1033"Yes," he said. "That is the way with him."
384−###### Produces:
1036+**Produces:**
386"Yes," he said. "That is the way with him."
1038"Yes," he said. "That is the way with him."
@@ -399,7 +1051,7 @@ bug.
402−##### Inline Code Literal
1054+#### Inline Code Literal
404Enclosing some text in
1056Enclosing some text in
@@ -417,7 +1069,7 @@ throughout this guide to `format text` to distinguish code from prose.
418`*[a 2 b c] -> *[*[a b] *[a c]]` is like lisp's `apply`.
1070`*[a 2 b c] -> *[*[a b] *[a c]]` is like lisp's `apply`.
420−###### Produces:
1072+**Produces:**
422`*[a 2 b c] -> *[*[a b] *[a c]]` is like lisp's `apply`.
1074`*[a 2 b c] -> *[*[a b] *[a c]]` is like lisp's `apply`.
@@ -431,13 +1083,13 @@ Hoon.
431The ++add arm is used to sum two numbers.
1083The ++add arm is used to sum two numbers.
434−###### Produces:
1086+**Produces:**
436The ++add arm is used to sum two numbers.
1088The ++add arm is used to sum two numbers.
438#### Block Code Literal
1090#### Block Code Literal
440−By enclosing a block of text in ``` on their own lines
1092+By enclosing a block of text in a tick on their own lines
441before and after the contained text, the text will be treated as a code block.
1093before and after the contained text, the text will be treated as a code block.
443Most of our examples so far have used.
1095Most of our examples so far have used.
@@ -456,7 +1108,7 @@ Most of our examples so far have used.
459−###### Produces:
1111+**Produces:**
462(def Y (fn [f]
1114(def Y (fn [f]
@@ -494,7 +1146,7 @@ Three or more hyphens, such as `---`, on their own line produce an `<hr>`
494element, the 'horizontal rule'. This is rendered as a horizontal line the
1146element, the 'horizontal rule'. This is rendered as a horizontal line the
495width of its containing paragraph.
1147width of its containing paragraph.
497−###### Example:
1149+**Example:**
500Above the line
1152Above the line
@@ -504,7 +1156,7 @@ Below the line
504And below this line, too
1156And below this line, too
507−###### Produces:
1159+**Produces:**
510Above the line
1162Above the line
@@ -537,7 +1189,7 @@ Quote break.
537 He is pale and thin, he wears a thin and ragged linen shirt.
1189 He is pale and thin, he wears a thin and ragged linen shirt.
540−###### Produces:
1192+**Produces:**
542> As Gregor Samsa awoke one morning from uneasy dreams
1194> As Gregor Samsa awoke one morning from uneasy dreams
543 he found himself transformed in his bed into a **monstrous** vermin.
1195 he found himself transformed in his bed into a **monstrous** vermin.
@@ -556,7 +1208,7 @@ normally in Udon, newlines are treated as spaces and do not create a
556new line of text. If you want to embed text where newlines are retained, then
1208new line of text. If you want to embed text where newlines are retained, then
557indent the text in question with **eight spaces**.
1209indent the text in question with **eight spaces**.
559−###### Example:
1211+**Example:**
562 A shape with lion body and the head of a man,
1214 A shape with lion body and the head of a man,
@@ -564,7 +1216,7 @@ indent the text in question with **eight spaces**.
564 Is moving its slow thighs, while all about it
1216 Is moving its slow thighs, while all about it
565 Reel shadows of the indignant desert birds.
1217 Reel shadows of the indignant desert birds.
567−###### Produces:
1219+**Produces:**
569 A shape with lion body and the head of a man,
1221 A shape with lion body and the head of a man,
570 A gaze blank and pitiless as the sun,
1222 A gaze blank and pitiless as the sun,
@@ -607,7 +1259,7 @@ Produces:
610−## A Simple Udon Blog
1262+## <a name="blog"></a>A Simple Udon Blog
612Publishing using Udon is really easy. It uses the file extension `.udon`. Here we'll create a very simple blog and publish our first posts.
1264Publishing using Udon is really easy. It uses the file extension `.udon`. Here we'll create a very simple blog and publish our first posts.
@@ -748,7 +1400,7 @@ Use `;join` to keep up with comments as they get posted:
749That's it! Easy.
1401That's it! Easy.
751−## A Static Site
1403+## <a name="static"></a>A Static Site
753Hosting a static tree of content is easy. Let's put together a really
1405Hosting a static tree of content is easy. Let's put together a really
754simple site for an imaginary Urbit meetup group.
1406simple site for an imaginary Urbit meetup group.