You can read this post with full editor features here.
2023-12-15
People often ask why Uiua doesn't have first-class functions. That is, functions that can be put on the stack and in arrays.
In the beginning, functions were normal array elements. Modifiers popped their functions from the stack like regular values. Functions could be put in arrays, and lists of functions even had some special uses. There was a ! call function which called the top function on the stack. Boxes were not even a dedicated type. They were just functions that took no arguments and returned a single value.
However, as Uiua's development continued, the language began to rely more and more on stack signatures being well-defined. This property catches errors early, enables some optimizations, and allows modifiers to behave differently depending on their function's siganture. That last point lets us avoid having multiple modifiers that work the same way but on different numbers of arguments. For example, Factor has the words bi, 2bi, 3bi, tri, 2tri, and 3tri. Uiua can express all of these and more with just
+ ⊃ fork
+ .
Unfortunately, having first-class functions was at odds with this design. Because functions could be put into arrays and (conditionally) moved around on the stack, the compiler was not able to determine the signature of a function that called a function value. This meant that anywhere the ! call function was used needed a signature annotation nearby, which you better hope was correct, or the code would break somewhere else. It also incurred additional interpreter overhead to get the functions from arrays and made certain types of optimizations impossible.
Other than these design and implementation concerns, the ability to move functions around on the stack made code much harder to read when it was used. You had to keep in your mind not only the values, but the functions that worked on them as well. They were another value you had to deal with, and the related stack manipulation could get quite messy.
And so I settled on a different approach. Functions were removed as an element type and were put elsewhere in the interpreter. Boxes became a type in their own right. The ! call function was removed, and ! was repurposed to be part of defining custom modifiers. Custom modifiers capture the primary use case of first-class functions: injecting some variable code into a function. While they are technically more limited, their uniform structure makes them easier to both read and write. This change also massively simplified the interpreter, as well as the complexity of the language itself.
Despite the downgrading of functions to second-class status, it should be noted that I do like functional programming languages. I just don't think that first-class functions are a good fit for Uiua. In practice, first-class functions are mostly unnecessary if you have higher-order functions, which array languages have had for decades. APL's operators, J's adverbs and conjunctions, and BQN and Uiua's modifiers are all versions of higher-order functions. They allow the mapping, reduction, and general transformation of data in the same way that first-class functions do in other languages.
Now if only I could find a way to get rid of boxes...
\ No newline at end of file
diff --git a/docs/blog/second-class-functions-text.md b/docs/blog/second-class-functions-text.md
new file mode 100644
index 000000000..38a7f254a
--- /dev/null
+++ b/docs/blog/second-class-functions-text.md
@@ -0,0 +1,21 @@
+# Why doesn't Uiua have first-class functions?
+
+2023-12-15
+
+---
+
+People often ask why Uiua doesn't have first-class functions. That is, functions that can be put on the stack and in arrays.
+
+In the beginning, functions *were* normal array elements. Modifiers popped their functions from the stack like regular values. Functions could be put in arrays, and lists of functions even had some special uses. There was a `! call` function which called the top function on the stack. Boxes were not even a dedicated type. They were just functions that took no arguments and returned a single value.
+
+However, as Uiua's development continued, the language began to rely more and more on stack signatures being well-defined. This property catches errors early, enables some optimizations, and allows modifiers to behave differently depending on their function's siganture. That last point lets us avoid having multiple modifiers that work the same way but on different numbers of arguments. For example, [Factor](https://factorcode.org/) has the words `bi`, `2bi`, `3bi`, `tri`, `2tri`, and `3tri`. Uiua can express all of these and more with just [fork]().
+
+Unfortunately, having first-class functions was at odds with this design. Because functions could be put into arrays and (conditionally) moved around on the stack, the compiler was not able to determine the signature of a function that called a function value. This meant that anywhere the `! call` function was used needed a signature annotation nearby, which you better hope was correct, or the code would break somewhere else. It also incurred additional interpreter overhead to get the functions from arrays and made certain types of optimizations impossible.
+
+Other than these design and implementation concerns, the ability to move functions around on the stack made code much harder to read when it was used. You had to keep in your mind not only the values, but the functions that worked on them as well. They were another value you had to deal with, and the related stack manipulation could get quite messy.
+
+And so I settled on a different approach. Functions were removed as an element type and were put elsewhere in the interpreter. Boxes became a type in their own right. The `! call` function was removed, and `!` was repurposed to be part of defining custom modifiers. [Custom modifiers](/docs/custommodifiers) capture the primary use case of first-class functions: injecting some variable code into a function. While they are technically more limited, their uniform structure makes them easier to both read and write. This change also massively simplified the interpreter, as well as the complexity of the language itself.
+
+Despite the downgrading of functions to second-class status, it should be noted that I do like functional programming languages. I just don't think that first-class functions are a good fit for Uiua. In practice, first-class functions are mostly unnecessary if you have higher-order functions, which array languages have had for decades. APL's operators, J's adverbs and conjunctions, and BQN and Uiua's modifiers are all versions of higher-order functions. They allow the mapping, reduction, and general transformation of data in the same way that first-class functions do in other languages.
+
+Now if only I could find a way to get rid of boxes...
\ No newline at end of file
diff --git a/docs/blog/subscripts-html.html b/docs/blog/subscripts-html.html
new file mode 100644
index 000000000..936bac793
--- /dev/null
+++ b/docs/blog/subscripts-html.html
@@ -0,0 +1,102 @@
+
+
+
+
+
You can read this post with full editor features here.
2024-11-25
If you get into any level of mathematics above a middle school level, you're likely to encounter notation that involves subscripts: little numbers or letters that sit across the baseline of the text and indicate different things about the thing to their left.
One common use of subscripts is to indicate indices. In many (perhaps the majoriy of?) programming languages, the subscript index notation of mathematics is replaced with the familiar [] square bracket syntax. Even APL, of which Uiua is a descendent, uses square brackets for this purpose. This is a nice, uniform syntax that is - critically - easy to type on an ASCII keyboard. But it loses a bit of the art, beauty, and expressiveness of mathematical notation.
Subscripts in Uiua
Uiua's formatter and its embrace of Unicode glyphs free it from the contraints many other languages have. This makes it possible to explore powerful and/or aesthetic syntactic constructs that would either be impossible or cumbersome to express in other languages. Look no further than the fancy module delimiters.
Uiua has actually allowed subscript numbers in identifiers for a while. Since identifiers cannot contain regular digits, this allows you to put numbers in them anyway.
Md₅ ← ∘ # TODO
+Sha₂₅₆ ← ∘ # TODO
Subscripts for use beyond identifiers were originally proposed in the Uiua discord as almost a joke. A whimsical syntax for modifying the behavior of certain functions and modifiers. But people got to talking about what could be possible, and I implemented subscripts as an experimental feature. At time of writing, subscripts have just been stabilized.
Uiua subscripts are written with two underscores __ followed by some digits. They can also be negative. The formatter will convert this into nice unicode subscript digits.
# Try formatting!
++__1 5 # 6
+×₂ 12 # 24 6
But what are they for? In the example above, they are equivalent to just not using them at all. For mathematical operators, they are only really good for reducing the number of parentheses needed. This is valuable in its own right for readability, but it is not reason enough to add an entire syntax for it.
However, subscripts on some functions and modifiers allow you to express things that would otherwise be impossible.
A brief history of Uiua's rank functionality
Uiua has gone through a few iterations of ways to express operating at a certain rank of an array. The other array languages simply have a rank operator that allows the direct specification of the rank to operate at. This approach works and is very general. At one point, Uiua had something similar in a modifier called ≑ level. This took a number or list of numbers indicating the ranks to operate at, as well as the function to operate on the array. While this worked, something about it never sat right with me. In an array language, the structure and rank of an array are, in most cases, the structure of the computation itself. There's something odd about having some numbers in your code that refer to actual numbers, and then other numbers that refer to the computation.
The first attempt to alleviate this discomfort I felt was the infamous Ocean Notation. It was a series of glyphs that had special parsing rules but whose function was only to create rank lists for use with level ≑ level. This mostly eliminated rank-indicating numbers from the code. While this system was kind of neat, it added too many new symbols for the programmer to learn with very little payoff, and it was not general enough to handle all cases.
≑ level was eventually replaced with Uiua's current system involving
+ ≡ rows
+ and
+ ¤ fix
+ . This system is simple, composable, and easy to learn. However, it cannot handle a common use of rank in other array languages: how do you operate on rank-N subarrays of an array of arbitrary rank? To fill this hole, the ☇ rerank function was added. This set the rank of the rows of an array to the given number. This also worked, and the system was complete.
But there were those numbers in the code again. You'd most often write ☇1 or ☇2 to change the rank of an array, collapsing the leading dimensions, sometimes temporarily. The thing is, you never need this number to be dynamic. It is always a number sitting there in the code itself, a static value, known at compile time. Sometimes it had to be relative to the rank of the array, in which case you would use a static negative number, but a static value nontheless.
Some uses of subscripts
As subscripts were experimented with, we realized that they could replace all uses of ☇ rerank.
Want to collapse an array to a certain rank? That's subscripted
+ ♭ deshape
+ .
What do you do when you want to collect some number of values from the stack into an array? The previous direction was to use []s or {}s with
+ ⊙ dip
+ and
+ ∘ identity
+ .
How do you take the Nth root of a number? Previously, you'd have to raise to the power of the reciprocal. Now you can just use subscripted
+ √ sqrt
+ .
ⁿ÷:1 3 125 # 5
+√₃ 125 # 5 5
Something similarly useful happens with
+ ⁅ round
+ .
⍜×⁅ 1e3 π # 3.142
+⁅₃ π # 3.142 3.142
Subscripts also solve the infamous problem of calling
+ ∩ both
+ on 3 sets of arguments.
[∩₃+ 1 2 3 4 5 6] # [3 7 11]
This is all to not even mention all the ways that subscripts simply help avoid parentheses, which reduces line noise and makes code easier to read.
You can find a full list of all the currently implemented subscripts here.
Going forward
One thing not listed above, and which is certainly more subjective, is that subscripts are pretty. They evoke the beauty of mathematical notation, a little number that you write to augment meaning. They make me smile! 😊
Much more is possible as well. One likely future use of subscripts is as a way to indicate non-base-10 numeric literals. Also, allowing for non-numeric subscripts would open up a whole new avenue of exploration.
I hope you enjoy this new feature. It is available in the online pad and in the latest release of the native interpreter.
\ No newline at end of file
diff --git a/docs/blog/subscripts-text.md b/docs/blog/subscripts-text.md
new file mode 100644
index 000000000..72a45d59e
--- /dev/null
+++ b/docs/blog/subscripts-text.md
@@ -0,0 +1,111 @@
+# Subscripts
+
+2024-11-25
+
+---
+
+If you get into any level of mathematics above a middle school level, you're likely to encounter notation that involves *subscripts*: little numbers or letters that sit across the baseline of the text and indicate different things about the thing to their left.
+
+![Matrix multiplication with subscript notation (invert)](https://wikimedia.org/api/rest_v1/media/math/render/svg/ee372c649dea0a05bf1ace77c9d6faf051d9cc8d)
+
+One common use of subscripts is to indicate indices. In many (perhaps the majoriy of?) programming languages, the subscript index notation of mathematics is replaced with the familiar `[]` square bracket syntax. Even APL, of which Uiua is a descendent, uses square brackets for this purpose. This is a nice, uniform syntax that is - critically - easy to type on an ASCII keyboard. But it loses a bit of the art, beauty, and expressiveness of mathematical notation.
+
+## Subscripts in Uiua
+
+Uiua's [formatter](https://www.uiua.org/tutorial/basic#formatting) and its embrace of Unicode glyphs free it from the contraints many other languages have. This makes it possible to explore powerful and/or aesthetic syntactic constructs that would either be impossible or cumbersome to express in other languages. Look no further than the [fancy module delimiters](https://www.uiua.org/tutorial/modules#scoped-modules).
+
+Uiua has actually allowed subscript numbers in identifiers for a while. Since identifiers cannot contain regular digits, this allows you to put numbers in them anyway.
+
+```uiua
+Md₅ ← ∘ # TODO
+Sha₂₅₆ ← ∘ # TODO
+```
+
+Subscripts for use beyond identifiers were originally proposed in the [Uiua discord](https://discord.gg/3r9nrfYhCc) as almost a joke. A whimsical syntax for modifying the behavior of certain functions and modifiers. But people got to talking about what could be possible, and I implemented subscripts as an experimental feature. At time of writing, subscripts have just been stabilized.
+
+Uiua subscripts are written with two underscores `__` followed by some digits. They can also be negative. The formatter will convert this into nice unicode subscript digits.
+
+```uiua
+# Try formatting!
++__1 5
+×₂ 12
+```
+
+But what are they for? In the example above, they are equivalent to just not using them at all. For mathematical operators, they are only really good for reducing the number of parentheses needed. This is valuable in its own right for readability, but it is not reason enough to add an entire syntax for it.
+
+However, subscripts on some functions and modifiers allow you to express things that would otherwise be impossible.
+
+## A brief history of Uiua's rank functionality
+
+Uiua has gone through a few iterations of ways to express operating at a certain *rank* of an array. The other array languages simply have a `rank` operator that allows the direct specification of the rank to operate at. This approach works and is very general. At one point, Uiua had something similar in a modifier called `≑ level`. This took a number or list of numbers indicating the ranks to operate at, as well as the function to operate on the array. While this worked, something about it never sat right with me. In an array language, the structure and rank of an array are, in most cases, the structure of the computation itself. There's something odd about having some numbers in your code that refer to actual *numbers*, and then other numbers that refer to the computation.
+
+The first attempt to alleviate this discomfort I felt was the infamous *Ocean Notation*. It was a series of glyphs that had special parsing rules but whose function was *only* to create rank lists for use with level `≑ level`. This mostly eliminated rank-indicating numbers from the code. While this system was kind of neat, it added too many new symbols for the programmer to learn with very little payoff, and it was not general enough to handle all cases.
+
+`≑ level` was eventually replaced with Uiua's current system involving [`≡ rows`](https://uiua.org/docs/rows) and [`¤ fix`](https://uiua.org/docs/fix). This system is simple, composable, and easy to learn. However, it cannot handle a common use of `rank` in other array languages: how do you operate on rank-N subarrays of an array of arbitrary rank? To fill this hole, the `☇ rerank` function was added. This set the rank of the *rows* of an array to the given number. This also worked, and the system was complete.
+
+But there were those numbers in the code again. You'd most often write `☇1` or `☇2` to change the rank of an array, collapsing the leading dimensions, sometimes temporarily. The thing is, you *never* need this number to be dynamic. It is *always* a number sitting there in the code itself, a static value, known at compile time. Sometimes it had to be relative to the rank of the array, in which case you would use a static negative number, but a static value nontheless.
+
+## Some uses of subscripts
+
+As subscripts were experimented with, we realized that they could replace all uses of `☇ rerank`.
+
+Want to collapse an array to a certain rank? That's subscripted [`♭ deshape`](https://uiua.org/docs/deshape).
+
+```uiua
+⍉ ♭₂ ⇡2_2_3
+```
+
+Want to call a function on all rank-N subarrays of an array? That's subscripted [`∵ each`](https://uiua.org/docs/each).
+
+```uiua
+∵₁□ °△2_3_4
+∵₂□ °△2_3_4
+```
+
+But there's more than just messing with rank!
+
+What do you do when you want to collect some number of values from the stack into an array? The previous direction was to use `[]`s or `{}`s with [`⊙ dip`](https://uiua.org/docs/dip) and [`∘ identity`](https://uiua.org/docs/identity).
+
+```uiua
+[⊙⊙⊙∘] 1 2 3 4
+{⊙⊙∘} 5 "Hi!" 1_2_3
+```
+
+But this is unnecessarily verbose. This can now be done with subscripted [`⊟ couple`](https://uiua.org/docs/couple) or [`□ box`](https://uiua.org/docs/box)!
+
+```uiua
+⊟₄ 1 2 3 4
+□₃ 5 "Hi!" 1_2_3
+```
+
+How do you take the Nth root of a number? Previously, you'd have to raise to the power of the reciprocal. Now you can just use subscripted [`√ sqrt`](https://uiua.org/docs/sqrt).
+
+```uiua
+ⁿ÷:1 3 125
+√₃ 125
+```
+
+Something similarly useful happens with [`⁅ round`](https://uiua.org/docs/round).
+
+```uiua
+⍜×⁅ 1e3 π
+⁅₃ π
+```
+
+Subscripts also solve the infamous problem of calling [`∩ both`](https://uiua.org/docs/both) on 3 sets of arguments.
+
+```uiua
+[∩₃+ 1 2 3 4 5 6]
+```
+
+This is all to not even mention all the ways that subscripts simply help avoid parentheses, which reduces line noise and makes code easier to read.
+
+You can find a full list of all the currently implemented subscripts [here](https://uiua.org/docs/subscripts).
+
+## Going forward
+
+One thing not listed above, and which is certainly more subjective, is that subscripts are *pretty*. They evoke the beauty of mathematical notation, a little number that you write to augment meaning. They make me smile! 😊
+
+Much more is possible as well. One likely future use of subscripts is as a way to indicate non-base-10 numeric literals. Also, allowing for non-numeric subscripts would open up a whole new avenue of exploration.
+
+I hope you enjoy this new feature. It is available in the [online pad](https://uiua.org/pad) and in the latest release of the [native interpreter](https://github.com/uiua-lang/uiua/releases).
\ No newline at end of file
diff --git a/docs/blog/uiua-0.10.0-html.html b/docs/blog/uiua-0.10.0-html.html
new file mode 100644
index 000000000..19be7d1d2
--- /dev/null
+++ b/docs/blog/uiua-0.10.0-html.html
@@ -0,0 +1,66 @@
+
+
+
+
+
This release contains so many changes, improvements, and new features that I thought it deserved a blog post.From here on, major releases will be announced in this way.
While there are many changes, I want to highlight a few of them here.
Pattern Matching
Using
+ ° un
+ on a constant value will now match a pattern. When used with
+ ⍣ try
+ , this can be used to conditionally match, extract, and process values.
The new &clget and &clset functions provide access to the clipboard.
The interpreter's built-in language server now supports many more features.
There are a ton more! Again, you can read the full changelog here.
💖
As always, I'd like to thank everyone who contributed to this release, whether by directly contributing code, reporting bugs, or just using Uiua and providing feedback.
Uiua is in many ways a novel and unique language, and I think it is only through our collective effort that we can properly explore its design space.
With your help, I hope to continue to improve Uiua to the point of stability.
\ No newline at end of file
diff --git a/docs/blog/uiua-0.10.0-text.md b/docs/blog/uiua-0.10.0-text.md
new file mode 100644
index 000000000..20fd84311
--- /dev/null
+++ b/docs/blog/uiua-0.10.0-text.md
@@ -0,0 +1,99 @@
+# Announcing Uiua 0.10.0
+
+2024-04-04
+
+---
+
+Uiua 0.10.0 is now available!
+
+You can find the full changelog [here](https://uiua.org/docs/changelog#0.10.0---2024-04-04).
+
+This release contains so many changes, improvements, and new features that I thought it deserved a blog post.
+From here on, major releases will be announced in this way.
+
+While there are many changes, I want to highlight a few of them here.
+
+## Pattern Matching
+
+Using [`un`](https://uiua.org/docs/un) on a constant value will now match a pattern. When used with [`try`](https://uiua.org/docs/try), this can be used to conditionally match, extract, and process values.
+
+```uiua
+F ← ⍣(
+ ×10 °[1⊙3] # Extract and multiply..
+| °(⊂5) # ..or remove leading 5..
+| ⇌ # ..else reverse
+)
+F [1 2 3]
+F [5 6 7]
+F "cool!"
+```
+You can read more in the [Pattern Matching](https://uiua.org/tutorial/patternmatching) tutorial.
+
+## Array Macros
+
+Array macros are a powerful new feature that allow full compile-time metaprogramming.
+
+They allow Uiua code to directly manipulate other Uiua code, enabling a wide range of new possibilities.
+
+```uiua
+F! ←^ ≡$"_ ← _\n" "ABC"
+F!(1|2|3)
+[A B C B B]
+```
+
+You can read more in the updated [Macros](https://uiua.org/tutorial/macros) tutorial.
+
+## Git Modules
+
+You can now prefix a module path with `git:` to import a git repository from a URL.
+```uiua
+~ "git: github.com/uiua-lang/example-module" ~ Upscale
+Upscale 3 [1_2 3_4]
+```
+In the native interpreter, this automatically creates a Git submodule.
+
+On the web, it fetches a `lib.ua` file from the repository.
+
+You can read more in the updated [Modules](https://uiua.org/tutorial/modules) tutorial.
+
+## [`mask`](https://uiua.org/docs/mask)
+
+[`mask`](https://uiua.org/docs/mask) is a new function that is similar to [`find`](https://uiua.org/docs/find), but it returns full masks of matches rather than just the first positions.
+
+```uiua
+⦷ " - " "Hey - how-are - you"
+```
+```uiua
+⊜□¬⦷⊙. " - " "Hey - how-are - you"
+```
+
+This simplifies a lot of string-processing code in particular. A new [strings](https://uiua.org/tutorial/strings) tutorial has been added as well.
+
+## Other Changes
+
+Switch functions now format to use `⟨⟩` brackets. This makes them easier to distinguish from function packs.
+```uiua
+F ← (×10|↥2)<2. # This..
+F ← ⟨×10|↥2⟩<2. # Formats to this
+F 0
+F 5
+```
+
+[`map`](https://uiua.org/docs/map) and related functions are no longer experimental! See the [`map`](https://uiua.org/docs/map) docs for an overview.
+```uiua
+map 1_2_3 4_5_6
+```
+
+The new [`&clget`](https://uiua.org/docs/&clget) and [`&clset`](https://uiua.org/docs/&clset) functions provide access to the clipboard.
+
+The interpreter's built-in language server now supports [many more features](https://marketplace.visualstudio.com/items?itemName=uiua-lang.uiua-vscode).
+
+There are a ton more! Again, you can read the full changelog [here](https://uiua.org/docs/changelog#0.10.0---2024-04-04).
+
+## 💖
+
+As always, I'd like to thank everyone who contributed to this release, whether by directly contributing code, reporting bugs, or just using Uiua and providing feedback.
+
+Uiua is in many ways a novel and unique language, and I think it is only through our collective effort that we can properly explore its design space.
+
+With your help, I hope to continue to improve Uiua to the point of stability.
\ No newline at end of file
diff --git a/docs/blog/uiua-0.11.0-html.html b/docs/blog/uiua-0.11.0-html.html
new file mode 100644
index 000000000..dc76bc2a3
--- /dev/null
+++ b/docs/blog/uiua-0.11.0-html.html
@@ -0,0 +1,174 @@
+
+
+
+
+
Uiua is a general purpose, stack-based, array-oriented programming language with a focus on tacit code.
While this release does not have any major new features, it extends the functionality of many primitives, optimizes many common patterns, and fixes a number of bugs.
+ / reduce
+ takes a dyadic function and applies it "between" all rows of an array.
/+ [1 2 3 4 5] # 15
+ / reduce
+ can now take multiple arguments if its function takes more than two arguments. Additional arguments are interspersed between the rows and are passed above the main array on the stack.
/(⊂⊂) 0 [1 2 3 4] # [1 0 2 0 3 0 4]
This is particularly useful when used with
+ ◇ content
+ and
+ ⊂ join
+ to intersperse a delimiter between a list of strings.
Array swizzles are written with a ⋊ followed by some letters. Rows from the array that correspond to the letters will be put on the stack. ⋊ formats from '' when followed by letters.
Swizzles are experimental and may change in future versions as their place in the language is explored.
The New Pad
Much of the code for the Uiua website pad has been rewritten. This new pad uses less custom behavior and should work better in more browsers.
If you are reading this on the Uiua website (with full editor features), then all the examples above use this new pad!
💗
Thank you as always to everyone who uses Uiua and helps with its development! Your enthusiasm for the language gives me life.
A special thanks to all of Uiua's sponsors for their continued support 🥰
Again, you can find the full changelog for this release here.
You can join the Uiua Discord to chat about the language, ask questions, or get help.
\ No newline at end of file
diff --git a/docs/blog/uiua-0.11.0-text.md b/docs/blog/uiua-0.11.0-text.md
new file mode 100644
index 000000000..fe8cbf1de
--- /dev/null
+++ b/docs/blog/uiua-0.11.0-text.md
@@ -0,0 +1,134 @@
+# Announcing Uiua 0.11.0
+
+2024-06-02
+
+---
+
+Uiua 0.11.0 is now available!
+
+You can find the full changelog [here](https://uiua.org/docs/changelog#0.11.0---2024-06-02).
+
+Uiua is a general purpose, stack-based, array-oriented programming language with a focus on tacit code.
+
+While this release does not have any major new features, it extends the functionality of many primitives, optimizes many common patterns, and fixes a number of bugs.
+
+Here are some of the highlights:
+
+## Multi-argument [`reduce /`](https://uiua.org/docs/reduce)
+
+[`reduce /`](https://uiua.org/docs/reduce) takes a dyadic function and applies it "between" all rows of an array.
+
+```uiua
+/+ [1 2 3 4 5]
+```
+
+[`reduce /`](https://uiua.org/docs/reduce) can now take multiple arguments if its function takes more than two arguments. Additional arguments are interspersed between the rows and are passed above the main array on the stack.
+
+```uiua
+/(⊂⊂) 0 [1 2 3 4]
+```
+
+This is particularly useful when used with [`content ◇`](https://uiua.org/docs/content) and [`join ⊂`](https://uiua.org/docs/join) to intersperse a delimiter between a list of strings.
+
+```uiua
+/◇(⊂⊂) @, {"cat" "dog" "bird" "fish"}
+```
+
+## [`json`](https://uiua.org/docs/json) and [`xlsx`](https://uiua.org/docs/xlsx)
+
+The [`json`](https://uiua.org/docs/json) and [`xlsx`](https://uiua.org/docs/xlsx) functions allow the encoding and decoding of JSON and XLSX data respectively.
+
+`json` converts an array to a JSON string.
+
+```uiua
+json [1 2 3 4]
+```
+
+It works with `map`s as well.
+
+```uiua
+json map {"name" "age"} {"Dan" 31}
+```
+
+[`un °`](https://uiua.org/docs/un) `json` decodes a JSON string.
+
+```uiua
+°json $ {"type": "requires", "content": "json", "ids": [38, 22, 5]}
+```
+
+`xlsx` is similar, but is works with binary data rather than strings.
+
+## [`take ↙`](https://uiua.org/docs/take)/[`drop ↘`](https://uiua.org/docs/drop) [`infinity ∞`](https://uiua.org/docs/infinity)
+
+[`take ↙`](https://uiua.org/docs/take) and [`drop ↘`](https://uiua.org/docs/drop) isolate part of an array.
+
+```uiua
+↙ 3 [1 2 3 4 5]
+↘ 3 [1 2 3 4 5]
+```
+
+Multidimensional indices have always been supported.
+
+```uiua
+↙2_2 . ↯3_4⇡12
+```
+
+You can now provide [`infinity ∞`](https://uiua.org/docs/infinity) as one or more of the indices to [`take ↙`](https://uiua.org/docs/take) or [`drop ↘`](https://uiua.org/docs/drop) that entire axis.
+
+```uiua
+↙∞_2 . ↯3_4⇡12
+```
+``` uiua
+↙1_∞_2 . ↯2_3_4⇡24
+```
+
+## Swizzles
+
+Swizzles are a new experimental feature that allow concise manipulation of the stack and extraction from arrays.
+
+Stack swizzles are written with a `λ` followed by some letters. The stack will be rearranged accordingly. `λ` formats from `'` when followed by letters.
+
+```uiua
+# Experimental!
+[λccab 1 2 3]
+```
+
+Capital letters will [`fix ¤`](https://uiua.org/docs/fix) the corresponding array. This is useful with complex [`rows ≡`](https://uiua.org/docs/rows) operations.
+
+```uiua
+# Experimental!
+≡(⊂⊂) ? λaBC 1_2 3_4 5_6
+```
+
+*Array* swizzles are written with a `⋊` followed by some letters. Rows from the array that correspond to the letters will be put on the stack. `⋊` formats from `''` when followed by letters.
+
+```uiua
+# Experimental!
+⋊beef [1 2 3 4 5 6]
+```
+
+Capital letters will [`un °`](https://uiua.org/docs/un) [`box ◻`](https://uiua.org/docs/box) the corresponding row.
+
+```uiua
+# Experimental!
+⋊aCB {"Dave" 31 [38 22 5]}
+```
+
+Swizzles are experimental and may change in future versions as their place in the language is explored.
+
+## The New Pad
+
+Much of the code for the [Uiua website pad](https://uiua.org/pad) has been rewritten. This new pad uses less custom behavior and should work better in more browsers.
+
+If you are reading this on the Uiua website (with full editor features), then all the examples above use this new pad!
+
+## 💗
+
+Thank you as always to everyone who uses Uiua and helps with its development! Your enthusiasm for the language gives me life.
+
+A *special* thanks to all of [Uiua's sponsors](https://github.com/sponsors/uiua-lang) for their continued support 🥰
+
+Again, you can find the full changelog for this release [here](https://uiua.org/docs/changelog#0.11.0---2024-06-02).
+
+You can join the [Uiua Discord](https://discord.gg/3r9nrfYhCc) to chat about the language, ask questions, or get help.
+
diff --git a/docs/blog/uiua-0.12.0-html.html b/docs/blog/uiua-0.12.0-html.html
new file mode 100644
index 000000000..72411756b
--- /dev/null
+++ b/docs/blog/uiua-0.12.0-html.html
@@ -0,0 +1,256 @@
+
+
+
+
+
As always, a heartfelt thank-you to everyone in the Uiua community! Your contributions are what make Uiua great.
If you want to support Uiua's development, you can become one of its excellent sponsors!
Again, you can find the full changelog for this release here.
You can join the Uiua Discord to chat about the language, ask questions, or get help.
Media Constants
A final fun note!
A few built-in image and audio constants have been added. These are useful for testing and demonstrating image and audio functions!
Logo
+▽⟜≡▽ 0.5 # Scales the image down
+Lena
+▽⟜≡▽ 0.5
+Music
\ No newline at end of file
diff --git a/docs/blog/uiua-0.12.0-text.md b/docs/blog/uiua-0.12.0-text.md
new file mode 100644
index 000000000..b761a12d3
--- /dev/null
+++ b/docs/blog/uiua-0.12.0-text.md
@@ -0,0 +1,199 @@
+# Announcing Uiua 0.12.0
+
+2024-08-16
+
+---
+
+Uiua 0.12.0 is now available!
+
+You can find the full changelog [here](https://uiua.org/docs/changelog#0.12.0---2024-08-16).
+
+Uiua is a general purpose, stack-based, array-oriented programming language with a focus on tacit code.
+
+This is a pretty big release! In addition to stable features, it contains a lot of experimental features to try out.
+
+Here are some of the highlights:
+
+## New Tutorials
+
+There are two new tutorials on the site:
+- [Tacit Code](https://uiua.org/tutorial/tacitcode)
+- [Code Tactility](https://uiua.org/tutorial/codetactility)
+
+## Scoped Modules
+
+Modules can now be declared without needing a new file.
+
+This is done with `---`s and a name.
+A `~` following the name lets you export names from within into the outer scope.
+
+```uiua
+---MyMod ~ Go
+ Foo ← 5
+ Go ← +1
+---
+Go MyMod~Foo
+```
+
+A module containing a function called `Call` or `New` can be called as a function.
+
+```uiua
+---Foo
+ Call ← /++1⇡
+---
+Foo 5
+```
+
+Using a module name as a macro (with a `!` at the end of the name) will make the module's names available inside that scope.
+
+```uiua
+---Foo
+ A ← 10
+ F ← +1
+ G ← ×2
+---
+Foo!(G F ×A) [1 2 3]
+```
+
+## [`switch ⨬`]()
+
+Dedicated switch function syntax has been replaced with the [`switch ⨬`](https://uiua.org/docs/switch) modifier.
+
+In addition, it has been expanded to do an implicit [`rows ≡`](https://uiua.org/docs/rows).
+
+```uiua
+⨬(∘|+1|×2) [0 1 2] 5
+```
+
+Existing `⟨⟩`s will continue to parse and will format to [`switch ⨬`](https://uiua.org/docs/switch) with a function pack.
+
+## Subscript digits in identifiers
+
+Unlike most programming languages, Uiua identifiers cannot contain digits.
+
+But sometimes you want digits in your names! You can now use *subscript* digits in identifiers.
+
+These format from a double underscore `__` followed by some digits.
+
+```uiua
+Sha__256 ← "todo" # This
+Sha₂₅₆ ← "todo" # Formats to this
+```
+
+## New Primitive Functionality
+
+Several primitive functions have new functionality
+
+[`un °`](https://uiua.org/docs/un) [`shape △`](https://uiua.org/docs/shape) now generates a [`range ⇡`](https://uiua.org/docs/range) array with the given shape.
+
+```uiua
+°△ 2_3_4
+```
+
+[`couple ⊟`](https://uiua.org/docs/couple) and [`join ⊂`](https://uiua.org/docs/join) are now more permissive of arguments with different ranks. The array with a smaller rank will be repeated.
+
+```uiua
+⊟ 1_2_3 4
+```
+```uiua
+⊂ [1_2_3 4_5_6] 7
+```
+
+[`keep ▽`](https://uiua.org/docs/keep) will now cycle the counts array.
+
+```uiua
+▽ 0_1_2 [1 2 3 4 5 6]
+```
+
+[`keep ▽`](https://uiua.org/docs/keep) also now allows a scalar non-integer to scale an array. This is useful for image and audio arrays.
+
+```uiua
+▽ 0.5 [1 2 3 4 5 6]
+▽ 1.5 [1 2 3 4 5 6]
+```
+## [`memberof ∈`](https://uiua.org/docs/memberof)
+
+[`member ∊`]() is now deprecated. It was almost always used along with [`flip :`]().
+
+It has been replaced with [`memberof ∈`](https://uiua.org/docs/memberof), which has the exact same functionality, except its arguments are flipped.
+
+```uiua
+F ← ∈"abc"
+F "beefcake"
+```
+
+This makes it work nicely with [`by ⊸`](https://uiua.org/docs/by)!
+
+```uiua
+⊜□¬⊸∈ " ," "To be, or not"
+```
+
+## Experimental Features
+
+This release adds a *lot* of experimental features to try out.
+
+While it's unlikely that all of these will be eventually stabilized, they are made available for you to try out and see how they feel.
+
+You can view to full list of experimental features [here](https://uiua.org/docs/experimental), but here are a few highlights:
+
+### More Stack Modifiers
+
+The [`with ⤙`](https://uiua.org/docs/with) and [`off ⤚`](https://uiua.org/docs/off) modifiers are complements to [`on ⟜`](https://uiua.org/docs/on) and [`by ⊸`](https://uiua.org/docs/by).
+
+[`with ⤙`](https://uiua.org/docs/with) keeps its function's *last* argument on *top* of the stack while [`off ⤚`](https://uiua.org/docs/off) keeps its function's *first* argument *below* the outputs on the stack.
+
+```uiua
+# Experimental!
+[⤙+ 2 5]
+[⤚+ 2 5]
+```
+
+The [`above ◠`](https://uiua.org/docs/above) and [`below ◡`](https://uiua.org/docs/below) modifiers keep *all* of a function's arguments above or below the outputs on the stack.
+
+```uiua
+# Experimental!
+[◠(++) 1 2 3]
+[◡(++) 1 2 3]
+```
+
+`chunks ⑄` is similar to [`windows ◫`](https://uiua.org/docs/windows) except the parts of the array do not overlap.
+
+```old-uiua
+# Experimental!
+⑄ 2_3 °△ 4_9
+≡≡□
+```
+
+[`orient ⤸`](https://uiua.org/docs/orient) transposes an array's axes by moving the axes at the given indices to the front of the [`shape △`](https://uiua.org/docs/shape).
+
+This simplifies complex shape transformations that would otherwise be done with several [`transpose ⍉`](https://uiua.org/docs/transpose)s and [`rows ≡`](https://uiua.org/docs/rows)s.
+
+```uiua
+# Experimental!
+°△ 2_3_4_5
+△ ⤸ 1_3
+```
+
+## 💖
+
+As always, a heartfelt thank-you to everyone in the Uiua community! Your contributions are what make Uiua great.
+
+If you want to support Uiua's development, you can become one of its excellent [sponsors](https://github.com/sponsors/uiua-lang)!
+
+Again, you can find the full changelog for this release [here](https://uiua.org/docs/changelog#0.12.0---2024-08-16).
+
+You can join the [Uiua Discord](https://discord.gg/3r9nrfYhCc) to chat about the language, ask questions, or get help.
+
+## Media Constants
+
+A final fun note!
+
+A few built-in image and audio constants have been added. These are useful for testing and demonstrating image and audio functions!
+
+```uiua
+Logo
+▽⟜≡▽ 0.5 # Scales the image down
+Lena
+▽⟜≡▽ 0.5
+Music
+```
diff --git a/docs/blog/uiua-0.13.0-html.html b/docs/blog/uiua-0.13.0-html.html
new file mode 100644
index 000000000..a92407dbe
--- /dev/null
+++ b/docs/blog/uiua-0.13.0-html.html
@@ -0,0 +1,221 @@
+
+
+
+
+
Top-level
+ ⍤ assert
+ ions are now interpreted as tests in some contexts. This includes in the website pad, or the uiua watch and uiua test commands, but not the uiua run command.
The native interpreter has two new commands: uiua find and uiua doc.
uiua find searches a file or directory for a string of formatted uiua code. This is useful when you cannot easily type some glyphs in your editor's default find interface.
uiua doc prints documentation for a function or modifier. That's it! It is the same documentation that is present on the website.
# Experimental!
This release added a lot of experimental features. Experimental features are not guaranteed to make it into the stable language, but they are added so they can be tried out.
Experimental features can be enabled by putting an # Experimental! comment at the top of a file.
Subscripts are an interesting way to augment the behavior of a function or modifier.
Subscript numbers may immediately follow a glyph. These can be typed with __ followed by some digits.
Also, check out Omnikar's awesome uiua-plot library for making plots and graphs in Uiua!
💟
Thanks as always to everyone in the Uiua community, and to Uiua's generous GitHub Sponsors!
Again, you can find the full changelog for this release here.
You can join the Uiua Discord to chat about the language, ask questions, or get help. We also do code challenges and discuss language features!
🐈⬛🐈
▽⟜≡▽ 0.5 Cats
\ No newline at end of file
diff --git a/docs/blog/uiua-0.13.0-text.md b/docs/blog/uiua-0.13.0-text.md
new file mode 100644
index 000000000..73eec4241
--- /dev/null
+++ b/docs/blog/uiua-0.13.0-text.md
@@ -0,0 +1,237 @@
+# Announcing Uiua 0.13.0
+
+2024-10-21
+
+---
+
+Uiua 0.13.0 is now available!
+
+You can find the full changelog [here](https://uiua.org/docs/changelog#0.13.0---2024-10-21).
+
+Uiua is a general purpose, stack-based, array-oriented programming language with a focus on tacit code.
+
+This release, like most, is the biggest one yet! Here are some highlights:
+
+## New Inverses
+
+A new inversion modifier, [`anti ⌝`](https://uiua.org/docs/anti), has been added.
+
+It captures certain useful inversion patterns. In general, it inverts a function as if its first argument were a constant.
+
+```uiua
+°(+1) 5
+⌝+ 1 5
+```
+
+This enables some useful functionality.
+
+```uiua
+⌝↘ 3 [1 2 3]
+⬚@.⌝⊏ 1_10_4_5 "abcd"
+```
+
+The new [`obverse ⌅`](https://uiua.org/docs/obverse) replaces, extends, unifies, and deprecates the existing `setinv` and `setund` modifiers.
+
+It allows you set multiple kinds of inverses at once.
+
+The [Inverses Tutorial](https://uiua.org/tutorial/inverses) has been updated to include [`anti ⌝`](https://uiua.org/docs/anti) and [`obverse ⌅`](https://uiua.org/docs/obverse).
+
+[`un °`](https://uiua.org/docs/un) [`by ⊸`](https://uiua.org/docs/by) can now be used to access the "undo" part of a function's [`under ⍜`](https://uiua.org/docs/under) functionality.
+
+This allows for "setter"-type behavior. For example, you can set the [`first ⊢`](https://uiua.org/docs/first) row of an array:
+
+```uiua
+°⊸⊢ 5 [1 2 3 4]
+```
+
+Or set the magnitude of a complex number:
+
+```uiua
+°⊸⌵ 10 . ℂ3 4
+```
+
+## New Stack Manipulation Modifiers
+
+The [`with ⤙`](https://uiua.org/docs/with) and [`below ◡`](https://uiua.org/docs/below) modifiers have been stabilized.
+
+[`with ⤙`](https://uiua.org/docs/with) keeps its function's last argument on top of the stack.
+
+```uiua
+⊟⤙+1 5
+⊂⤙⊡1 "hello"
+```
+
+[`below ◡`](https://uiua.org/docs/below) preserves a function's arguments below its outputs on the stack.
+
+```uiua
+[◡+] 1 2
+```
+
+```uiua
+∩▽◡¬ ⊸◿2 [1 2 3 4 5]
+```
+
+## [`orient ⤸`](https://uiua.org/docs/orient)
+
+[`orient ⤸`](https://uiua.org/docs/orient) has been stabilized. It reorders the axes of an array, rearranging the elements as necessary.
+
+```uiua
+°△3_3_2
+{⊙∘} ⤙⤸1
+```
+
+[`anti ⌝`](https://uiua.org/docs/anti)[`orient ⤸`](https://uiua.org/docs/orient) allows you to combine axes, which is equivalent to taking the diagonal along those axes.
+
+```uiua
+°△3_3
+⌝⤸ 0_0 .
+```
+
+## [`assert ⍤`](https://uiua.org/docs/assert) Tests
+
+Top-level [`assert ⍤`](https://uiua.org/docs/assert)ions are now interpreted as tests in some contexts. This includes in the website pad, or the `uiua watch` and `uiua test` commands, but *not* the `uiua run` command.
+
+```uiua
+⍤⤙≍ 3 +1 2
+⍤⤙≍ [1 2 3] ⊂1 [2 3]
+⍤⤙≍ "Hello" ⍜⊢⌵ "hello"
+```
+
+## Formatter Changes
+
+Consecutive single-line bindings now have their `←`s aligned. Try formatting this example:
+
+```uiua
+F ← +1
+Avg ← ÷⧻⟜/+
+Re ← ◌°ℂ
+```
+
+Modules now use fancy delimiters. They format from the existing `---`s. Try it out!
+
+```uiua
+---MyModule
+ F = +*10
+---
+```
+
+## Line Manipulation
+
+The behavior of `;` and `;;` has been changed.
+
+The main useful change is the formatter will reverse code that is separated by `;`s, so you don't have to press `←` quite as much.
+
+Try it out:
+
+```uiua
+1 2;+; *10 # Format!
+```
+
+You can read more about this functionality [here](https://uiua.org/tutorial/codetactility#line-manipulation).
+
+## New CLI Commands
+
+The native interpreter has two new commands: `uiua find` and `uiua doc`.
+
+`uiua find` searches a file or directory for a string of formatted uiua code. This is useful when you cannot easily type some glyphs in your editor's default find interface.
+
+`uiua doc` prints documentation for a function or modifier. That's it! It is the same documentation that is present on the website.
+
+## `# Experimental!`
+
+This release added a lot of experimental features. Experimental features are not guaranteed to make it into the stable language, but they are added so they can be tried out.
+
+Experimental features can be enabled by putting an `# Experimental!` comment at the top of a file.
+
+[**Subscripts**](https://uiua.org/docs/experimental#subscripts) are an interesting way to augment the behavior of a function or modifier.
+
+Subscript numbers may immediately follow a glyph. These can be typed with `__` followed by some digits.
+
+```uiua
+# Experimental!
+[∩__3+ 1 2 3 4 5 6] # Try formatting!
+```
+
+```uiua
+# Experimental!
+√₃ 27
+√₄ 625
+```
+
+```uiua
+# Experimental!
+⁅₃ π
+```
+
+```uiua
+# Experimental!
+⊟₄ 1 2 3 4
+□₃ "abc" 5 °△2_3
+```
+
+```uiua
+# Experimental!
+⍜(×10|-2) 5
+⍜×₁₀-₂ 5
+```
+
+Subscript behavior is not defined in a general way. Each function or modifier may interpret a subscript differently.
+
+All behaviors are specified [here](https://uiua.org/docs/experimental#subscript-modifiers).
+
+[**Data Definitions**](https://uiua.org/docs/experimental#data-definitions) define a module that has a constructor and getters. The constructed object is just a normal array.
+
+```uiua
+# Experimental!
+~Foo {Bar Baz}
+Foo 1 "Hi"
+Foo~Baz .
+```
+
+```uiua
+# Experimental!
+~Color [r g b a ← 1]
+Color 0.5 1 0.2
+Color!(+r⟜b) .
+```
+
+`enum`-like constructs are also possible. These automatically add tags to the array to disambiguate variants.
+
+```uiua
+# Experimental!
+┌─╴Foo
+ |Bar {A B}
+ |Baz [x y z]
+ |Qux
+└─╴
+Foo~Bar "Neat" "Cool"
+Foo~Baz 1 2 4
+Foo~Qux
+```
+
+You can read about everything data definitions can do [here](https://uiua.org/docs/experimental#data-definitions).
+
+## Contributors
+
+No previous Uiua release has had so many direct code contributions!
+
+In particular, I'd like to thank:
+- [Omnikar](https://github.com/omnikar/) for implementing [`un °`](https://uiua.org/docs/un)[`by ⊸`](https://uiua.org/docs/by)
+- [amatgil](https://github.com/amatgil) for implementing the new behavior for [`gen`](https://uiua.org/docs/gen) and the experimental [`around ’`](https://uiua.org/docs/around) function
+- [Marcos-cat](https://github.com/Marcos-cat/) for implementing [`fill ⬚`](https://uiua.org/docs/fill)ed [`csv`](https://uiua.org/docs/csv), [`memberof ∈`](https://uiua.org/docs/memberof)[`range ⇡`](https://uiua.org/docs/range) optimization, and a more persistent pad virtual filesystem
+
+Also, check out [Omnikar](https://github.com/omnikar/)'s awesome [`uiua-plot`](https://github.com/omnikar/uiua-plot) library for making plots and graphs in Uiua!
+
+## 💟
+
+Thanks as always to everyone in the Uiua community, and to Uiua's generous [GitHub Sponsors](https://github.com/sponsors/uiua-lang)!
+
+Again, you can find the full changelog for this release [here](https://uiua.org/docs/changelog#0.13.0---2024-10-21).
+
+You can join the [Uiua Discord](https://discord.gg/3r9nrfYhCc) to chat about the language, ask questions, or get help. We also do code challenges and discuss language features!
+
+## 🐈⬛🐈
+
+```uiua
+▽⟜≡▽ 0.5 Cats
+```
\ No newline at end of file
diff --git a/docs/blog/what-will-1-look-like-html.html b/docs/blog/what-will-1-look-like-html.html
new file mode 100644
index 000000000..8d1db4a8e
--- /dev/null
+++ b/docs/blog/what-will-1-look-like-html.html
@@ -0,0 +1,5 @@
+
+
+
+
+
You can read this post with full editor features here.
2024-01-19
The Uiua pad page prominently displays the words "Uiua is not yet stable". And so it has been asked: when will Uiua be stable? What features will it have? Is there a roadmap?
This post is to organize and present my thoughts on the future of Uiua.
Stability
Uiua will be made officially stable only after it has been unofficially stable for some time. That is, not until no breaking changes have been made for a long time.
The following language features will need to be nailed down before Uiua can ever be stable.
Stack manipulation
I think working with the stack, at least for up to 3 values, has become mostly pretty nice. However, things start to get complicated when working with more values, as is often necessary. There is some design work to be done here, and it's not out of the question that a very small amount of non-tacitness could be introduced to improve this.
The experimental bind modifier is a potential solution to this problem.
There is a balance to be struc between Uiua's goal of tacitness and its goal of being ergonomic. While the beauty of fully tacit code is a worthy goal, some problems involve data flows that are inherently complex, and so some kind of labeling system may be necessary to make such problems workable.
Box Ergonomics
While I've explored alternatives, I've come to the conclusion that nested arrays are a necessary pest. The data we work with is often nested or ragged, and while there are ways to represent such data with flat structures, those representations are cumbersome in their own ways.
And so boxes are likely here to stay. However, I do think some design work can be done to improve their ergonomics. Currently, Uiua's boxes are very similar to J's, but I think it may be worth it to make their usage a bit more implicit in some cases, closer to the nested arrays of APL or BQN.
System APIs
The current system functions are useful and mostly work. There are definitely implementation gaps which need to be filled. There are a good number of missing filesystem operations, and some other things like UDP sockets and proper interaction with child processes still need to be implemented.
FFI
An FFI system similar to BQN's is planned. This will allow Uiua to call into C libraries and will enable a lot more functionality.
\ No newline at end of file
diff --git a/docs/blog/what-will-1-look-like-text.md b/docs/blog/what-will-1-look-like-text.md
new file mode 100644
index 000000000..3e285a0af
--- /dev/null
+++ b/docs/blog/what-will-1-look-like-text.md
@@ -0,0 +1,37 @@
+# What will Uiua 1.0 look like?
+
+2024-01-19
+
+---
+
+The [Uiua pad](https://uiua.org/pad) page prominently displays the words "Uiua is not yet stable". And so it has been asked: when will Uiua be stable? What features will it have? Is there a roadmap?
+
+This post is to organize and present my thoughts on the future of Uiua.
+
+## Stability
+
+Uiua will be made officially stable only after it has been unofficially stable for some time. That is, not until no breaking changes have been made for a long time.
+
+The following language features will need to be nailed down before Uiua can ever be stable.
+
+### Stack manipulation
+
+I think working with the stack, at least for up to 3 values, has become mostly pretty nice. However, things start to get complicated when working with more values, as is often necessary. There is some design work to be done here, and it's not out of the question that a very small amount of non-tacitness could be introduced to improve this.
+
+The experimental [`bind`](https://uiua.org/docs/experimental#swizzles) modifier is a potential solution to this problem.
+
+There is a balance to be struc between Uiua's goal of tacitness and its goal of being ergonomic. While the beauty of fully tacit code is a worthy goal, some problems involve data flows that are inherently complex, and so some kind of labeling system may be necessary to make such problems workable.
+
+### Box Ergonomics
+
+While I've explored alternatives, I've come to the conclusion that nested arrays are a necessary pest. The data we work with is often nested or ragged, and while there are ways to represent such data with flat structures, those representations are cumbersome in their own ways.
+
+And so boxes are likely here to stay. However, I do think some design work can be done to improve their ergonomics. Currently, Uiua's boxes are very similar to J's, but I think it may be worth it to make their usage a bit more implicit in some cases, closer to the nested arrays of APL or BQN.
+
+### System APIs
+
+The current [system functions](https://uiua.org/docs/system) are useful and *mostly* work. There are definitely implementation gaps which need to be filled. There are a good number of missing filesystem operations, and some other things like UDP sockets and proper interaction with child processes still need to be implemented.
+
+### FFI
+
+An FFI system similar to [BQN's](https://mlochbaum.github.io/BQN/spec/system.html#foreign-function-interface) is planned. This will allow Uiua to call into C libraries and will enable a lot more functionality.
\ No newline at end of file
diff --git a/docs/combinators/B.svg b/docs/combinators/B.svg
new file mode 100644
index 000000000..d0141a4a7
--- /dev/null
+++ b/docs/combinators/B.svg
@@ -0,0 +1,18 @@
+
diff --git a/docs/combinators/B1.svg b/docs/combinators/B1.svg
new file mode 100644
index 000000000..8d3f486a1
--- /dev/null
+++ b/docs/combinators/B1.svg
@@ -0,0 +1,20 @@
+
diff --git a/docs/combinators/C.svg b/docs/combinators/C.svg
new file mode 100644
index 000000000..f46334fbd
--- /dev/null
+++ b/docs/combinators/C.svg
@@ -0,0 +1,18 @@
+
diff --git a/docs/combinators/D.svg b/docs/combinators/D.svg
new file mode 100644
index 000000000..c2fe4eac6
--- /dev/null
+++ b/docs/combinators/D.svg
@@ -0,0 +1,20 @@
+
diff --git a/docs/combinators/D2.svg b/docs/combinators/D2.svg
new file mode 100644
index 000000000..fe50b09b8
--- /dev/null
+++ b/docs/combinators/D2.svg
@@ -0,0 +1,22 @@
+
diff --git a/docs/combinators/E.svg b/docs/combinators/E.svg
new file mode 100644
index 000000000..5c3a8cffd
--- /dev/null
+++ b/docs/combinators/E.svg
@@ -0,0 +1,22 @@
+
diff --git a/docs/combinators/I.svg b/docs/combinators/I.svg
new file mode 100644
index 000000000..80d52f060
--- /dev/null
+++ b/docs/combinators/I.svg
@@ -0,0 +1,16 @@
+
diff --git a/docs/combinators/K.svg b/docs/combinators/K.svg
new file mode 100644
index 000000000..062b3378d
--- /dev/null
+++ b/docs/combinators/K.svg
@@ -0,0 +1,17 @@
+
diff --git a/docs/combinators/KI.svg b/docs/combinators/KI.svg
new file mode 100644
index 000000000..5cadf169d
--- /dev/null
+++ b/docs/combinators/KI.svg
@@ -0,0 +1,17 @@
+
diff --git a/docs/combinators/N.svg b/docs/combinators/N.svg
new file mode 100644
index 000000000..9643dbb4b
--- /dev/null
+++ b/docs/combinators/N.svg
@@ -0,0 +1,21 @@
+
diff --git a/docs/combinators/R.svg b/docs/combinators/R.svg
new file mode 100644
index 000000000..dbcfa1fe2
--- /dev/null
+++ b/docs/combinators/R.svg
@@ -0,0 +1,24 @@
+
diff --git a/docs/combinators/S.svg b/docs/combinators/S.svg
new file mode 100644
index 000000000..2e8510928
--- /dev/null
+++ b/docs/combinators/S.svg
@@ -0,0 +1,19 @@
+
diff --git a/docs/combinators/W.svg b/docs/combinators/W.svg
new file mode 100644
index 000000000..f18e0bf70
--- /dev/null
+++ b/docs/combinators/W.svg
@@ -0,0 +1,17 @@
+
diff --git a/docs/combinators/X.svg b/docs/combinators/X.svg
new file mode 100644
index 000000000..68122545f
--- /dev/null
+++ b/docs/combinators/X.svg
@@ -0,0 +1,23 @@
+
diff --git "a/docs/combinators/\303\212.svg" "b/docs/combinators/\303\212.svg"
new file mode 100644
index 000000000..da7520a2a
--- /dev/null
+++ "b/docs/combinators/\303\212.svg"
@@ -0,0 +1,26 @@
+
diff --git "a/docs/combinators/\316\224.svg" "b/docs/combinators/\316\224.svg"
new file mode 100644
index 000000000..bdbd02c8e
--- /dev/null
+++ "b/docs/combinators/\316\224.svg"
@@ -0,0 +1,20 @@
+
diff --git "a/docs/combinators/\316\243.svg" "b/docs/combinators/\316\243.svg"
new file mode 100644
index 000000000..ce48a6127
--- /dev/null
+++ "b/docs/combinators/\316\243.svg"
@@ -0,0 +1,19 @@
+
diff --git "a/docs/combinators/\316\246.svg" "b/docs/combinators/\316\246.svg"
new file mode 100644
index 000000000..c759a13b2
--- /dev/null
+++ "b/docs/combinators/\316\246.svg"
@@ -0,0 +1,21 @@
+
diff --git "a/docs/combinators/\316\2461.svg" "b/docs/combinators/\316\2461.svg"
new file mode 100644
index 000000000..ebd1fdda1
--- /dev/null
+++ "b/docs/combinators/\316\2461.svg"
@@ -0,0 +1,24 @@
+
diff --git "a/docs/combinators/\316\250.svg" "b/docs/combinators/\316\250.svg"
new file mode 100644
index 000000000..040805e33
--- /dev/null
+++ "b/docs/combinators/\316\250.svg"
@@ -0,0 +1,22 @@
+
diff --git "a/docs/combinators/\316\265.svg" "b/docs/combinators/\316\265.svg"
new file mode 100644
index 000000000..5cb9c981b
--- /dev/null
+++ "b/docs/combinators/\316\265.svg"
@@ -0,0 +1,22 @@
+
diff --git "a/docs/combinators/\316\275.svg" "b/docs/combinators/\316\275.svg"
new file mode 100644
index 000000000..0782f4f1d
--- /dev/null
+++ "b/docs/combinators/\316\275.svg"
@@ -0,0 +1,21 @@
+
diff --git "a/docs/combinators/\317\201.svg" "b/docs/combinators/\317\201.svg"
new file mode 100644
index 000000000..b830f38ef
--- /dev/null
+++ "b/docs/combinators/\317\201.svg"
@@ -0,0 +1,24 @@
+
diff --git "a/docs/combinators/\317\207.svg" "b/docs/combinators/\317\207.svg"
new file mode 100644
index 000000000..60762eea6
--- /dev/null
+++ "b/docs/combinators/\317\207.svg"
@@ -0,0 +1,23 @@
+
diff --git a/docs/favicon-crayon.ico b/docs/favicon-crayon.ico
new file mode 100644
index 000000000..5b372be8d
Binary files /dev/null and b/docs/favicon-crayon.ico differ
diff --git a/docs/favicon.ico b/docs/favicon.ico
new file mode 100644
index 000000000..9d7d73432
Binary files /dev/null and b/docs/favicon.ico differ
diff --git a/docs/index.html b/docs/index.html
new file mode 100644
index 000000000..211caa3b8
--- /dev/null
+++ b/docs/index.html
@@ -0,0 +1,121 @@
+
+
+
+
+ Uiua
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Uiua (wee-wuh) is a general purpose, stack-based,
+ array-oriented programming language with a focus on simplicity, beauty, and tacit code.
+
Uiua lets you write code that is as short as possible while remaining readable, so you can
+ focus on problems rather than ceremony.
+
The language is not yet stable, as its design space is still being explored. However, it is
+ already quite powerful and fun to use!
+
+
Loading...
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/primitives.json b/docs/primitives.json
new file mode 100644
index 000000000..f83beb9b8
--- /dev/null
+++ b/docs/primitives.json
@@ -0,0 +1,1424 @@
+{
+ "&ap": {
+ "args": 1,
+ "outputs": 0,
+ "class": "Media",
+ "description": "Play some audio"
+ },
+ "&args": {
+ "args": 0,
+ "outputs": 1,
+ "class": "Env",
+ "description": "Get the command line arguments"
+ },
+ "&asr": {
+ "args": 0,
+ "outputs": 1,
+ "class": "Media",
+ "description": "Get the sample rate of the audio output backend"
+ },
+ "&ast": {
+ "args": 0,
+ "outputs": 0,
+ "modifier_args": 1,
+ "class": "Media",
+ "description": "Synthesize and stream audio"
+ },
+ "&camcap": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Misc",
+ "description": "Capture an image from a webcam"
+ },
+ "&cd": {
+ "args": 1,
+ "outputs": 0,
+ "class": "Filesystem",
+ "description": "Change the current directory"
+ },
+ "&cl": {
+ "args": 1,
+ "outputs": 0,
+ "class": "Stream",
+ "description": "Close a stream by its handle"
+ },
+ "&clip": {
+ "args": 0,
+ "outputs": 1,
+ "class": "Misc",
+ "description": "Get the contents of the clipboard"
+ },
+ "&ep": {
+ "args": 1,
+ "outputs": 0,
+ "class": "StdIO",
+ "description": "Print a value to stderr followed by a newline"
+ },
+ "&epf": {
+ "args": 1,
+ "outputs": 0,
+ "class": "StdIO",
+ "description": "Print a value to stderr"
+ },
+ "&exit": {
+ "args": 1,
+ "outputs": 0,
+ "class": "Misc",
+ "description": "Exit the program with a status code"
+ },
+ "&fc": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Filesystem",
+ "description": "Create a file and return a handle to it"
+ },
+ "&fde": {
+ "args": 1,
+ "outputs": 0,
+ "class": "Filesystem",
+ "description": "Delete a file or directory"
+ },
+ "&fe": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Filesystem",
+ "description": "Check if a file, directory, or symlink exists at a path"
+ },
+ "&ffi": {
+ "args": 2,
+ "outputs": 1,
+ "class": "Ffi",
+ "description": "Call a foreign function interface",
+ "experimental": true
+ },
+ "&fif": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Filesystem",
+ "description": "Check if a path is a file"
+ },
+ "&fld": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Filesystem",
+ "description": "List the contents of a directory"
+ },
+ "&fmd": {
+ "args": 1,
+ "outputs": 0,
+ "class": "Filesystem",
+ "description": "Create a directory"
+ },
+ "&fo": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Filesystem",
+ "description": "Open a file and return a handle to it"
+ },
+ "&frab": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Filesystem",
+ "description": "Read all the contents of a file into a byte array"
+ },
+ "&fras": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Filesystem",
+ "description": "Read all the contents of a file into a string"
+ },
+ "&ftr": {
+ "args": 1,
+ "outputs": 0,
+ "class": "Filesystem",
+ "description": "Move a file or directory to the trash"
+ },
+ "&fwa": {
+ "args": 2,
+ "outputs": 0,
+ "class": "Filesystem",
+ "description": "Write the entire contents of an array to a file"
+ },
+ "&gifs": {
+ "args": 2,
+ "outputs": 0,
+ "class": "Media",
+ "description": "Show a gif"
+ },
+ "&httpsw": {
+ "args": 2,
+ "outputs": 1,
+ "class": "Tcp",
+ "description": "Make an HTTP(S) request",
+ "deprecated": true
+ },
+ "&ims": {
+ "args": 1,
+ "outputs": 0,
+ "class": "Media",
+ "description": "Show an image"
+ },
+ "&invk": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Command",
+ "description": "Invoke a path with the system's default program"
+ },
+ "&memcpy": {
+ "args": 3,
+ "outputs": 1,
+ "class": "Ffi",
+ "description": "Copy data from a pointer into an array",
+ "experimental": true
+ },
+ "&memfree": {
+ "args": 1,
+ "outputs": 0,
+ "class": "Ffi",
+ "description": "Free a pointer",
+ "experimental": true
+ },
+ "&p": {
+ "args": 1,
+ "outputs": 0,
+ "class": "StdIO",
+ "description": "Print a value to stdout followed by a newline"
+ },
+ "&pf": {
+ "args": 1,
+ "outputs": 0,
+ "class": "StdIO",
+ "description": "Print a value to stdout"
+ },
+ "&raw": {
+ "args": 1,
+ "outputs": 0,
+ "class": "Env",
+ "description": "Set the terminal to raw mode"
+ },
+ "&rb": {
+ "args": 2,
+ "outputs": 1,
+ "class": "Stream",
+ "description": "Read at most n bytes from a stream"
+ },
+ "&rs": {
+ "args": 2,
+ "outputs": 1,
+ "class": "Stream",
+ "description": "Read characters formed by at most n bytes from a stream"
+ },
+ "&ru": {
+ "args": 2,
+ "outputs": 1,
+ "class": "Stream",
+ "description": "Read from a stream until a delimiter is reached"
+ },
+ "&runc": {
+ "args": 1,
+ "outputs": 3,
+ "class": "Command",
+ "description": "Run a command and wait for it to finish"
+ },
+ "&runi": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Command",
+ "description": "Run a command and wait for it to finish"
+ },
+ "&runs": {
+ "args": 1,
+ "outputs": 3,
+ "class": "Command",
+ "description": "Run a command with streaming IO"
+ },
+ "&s": {
+ "args": 1,
+ "outputs": 0,
+ "class": "StdIO",
+ "description": "Print a nicely formatted representation of a value to stdout"
+ },
+ "&sc": {
+ "args": 0,
+ "outputs": 1,
+ "class": "StdIO",
+ "description": "Read a line from stdin"
+ },
+ "&sl": {
+ "args": 1,
+ "outputs": 0,
+ "class": "Misc",
+ "description": "Sleep for n seconds"
+ },
+ "&tcpa": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Tcp",
+ "description": "Accept a connection with a TCP or TLS listener"
+ },
+ "&tcpaddr": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Tcp",
+ "description": "Get the connection address of a TCP socket"
+ },
+ "&tcpc": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Tcp",
+ "description": "Create a TCP socket and connect it to an address"
+ },
+ "&tcpl": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Tcp",
+ "description": "Create a TCP listener and bind it to an address"
+ },
+ "&tcpsnb": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Tcp",
+ "description": "Set a TCP socket to non-blocking mode"
+ },
+ "&tcpsrt": {
+ "args": 2,
+ "outputs": 0,
+ "class": "Tcp",
+ "description": "Set the read timeout of a TCP socket in seconds"
+ },
+ "&tcpswt": {
+ "args": 2,
+ "outputs": 0,
+ "class": "Tcp",
+ "description": "Set the write timeout of a TCP socket in seconds"
+ },
+ "&tlsc": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Tcp",
+ "description": "Create a TCP socket with TLS support"
+ },
+ "&tlsl": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Tcp",
+ "description": "Create a TLS listener and bind it to an address",
+ "experimental": true
+ },
+ "&ts": {
+ "args": 0,
+ "outputs": 1,
+ "class": "Env",
+ "description": "Get the size of the terminal"
+ },
+ "&var": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Env",
+ "description": "Get the value of an environment variable"
+ },
+ "&w": {
+ "args": 2,
+ "outputs": 0,
+ "class": "Stream",
+ "description": "Write an array to a stream"
+ },
+ "above": {
+ "glyph": "◠",
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "Stack",
+ "description": "Keep all arguments to a function above the outputs on the stack",
+ "experimental": true
+ },
+ "absolute value": {
+ "glyph": "⌵",
+ "args": 1,
+ "outputs": 1,
+ "class": "MonadicPervasive",
+ "description": "Get the absolute value of a number"
+ },
+ "add": {
+ "glyph": "+",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicPervasive",
+ "description": "Add values"
+ },
+ "anti": {
+ "glyph": "⌝",
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "InversionModifier",
+ "description": "Invert the behavior of a function, treating its first argument as a constant"
+ },
+ "around": {
+ "ascii": "'",
+ "glyph": "’",
+ "args": 2,
+ "outputs": 3,
+ "class": "Stack",
+ "description": "Duplicate the top value on the stack to the third-to-top position",
+ "experimental": true
+ },
+ "assert": {
+ "glyph": "⍤",
+ "args": 2,
+ "outputs": 0,
+ "class": "Misc",
+ "description": "Throw an error if a condition is not met"
+ },
+ "astar": {
+ "outputs": 2,
+ "modifier_args": 3,
+ "class": "Misc",
+ "description": "Find shortest paths in a graph",
+ "experimental": true
+ },
+ "atangent": {
+ "glyph": "∠",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicPervasive",
+ "description": "Take the arctangent of two numbers"
+ },
+ "audio": {
+ "args": 3,
+ "outputs": 1,
+ "class": "Encoding",
+ "description": "Encode audio into a byte array"
+ },
+ "backward": {
+ "glyph": "𝄈",
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "Stack",
+ "description": "Call a function with its arguments reversed",
+ "experimental": true
+ },
+ "base": {
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicArray",
+ "description": "Get the base digits of a number",
+ "experimental": true
+ },
+ "below": {
+ "glyph": "◡",
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "Stack",
+ "description": "Keep all arguments to a function below the outputs on the stack"
+ },
+ "binary": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Encoding",
+ "description": "Encode an array into a compact binary representation",
+ "experimental": true
+ },
+ "bits": {
+ "glyph": "⋯",
+ "args": 1,
+ "outputs": 1,
+ "class": "MonadicArray",
+ "description": "Encode an array as bits (LSB-first)"
+ },
+ "both": {
+ "glyph": "∩",
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "Planet",
+ "description": "Call a function on two sets of values"
+ },
+ "box": {
+ "glyph": "□",
+ "args": 1,
+ "outputs": 1,
+ "class": "MonadicArray",
+ "description": "Turn an array into a box"
+ },
+ "bracket": {
+ "glyph": "⊓",
+ "outputs": 1,
+ "modifier_args": 2,
+ "class": "Planet",
+ "description": "Call two functions on two distinct sets of values"
+ },
+ "by": {
+ "glyph": "⊸",
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "Stack",
+ "description": "Duplicate a function's last argument before calling it"
+ },
+ "case": {
+ "glyph": "⍩",
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "Misc",
+ "description": "Call a pattern matching case",
+ "experimental": true
+ },
+ "ceiling": {
+ "glyph": "⌈",
+ "args": 1,
+ "outputs": 1,
+ "class": "MonadicPervasive",
+ "description": "Round to the nearest integer towards ∞"
+ },
+ "choose": {
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicArray",
+ "description": "Get all combinations of k rows from an array",
+ "experimental": true,
+ "deprecated": true
+ },
+ "chunks": {
+ "glyph": "⑄",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicArray",
+ "description": "Get the n-wise chunks of an array",
+ "experimental": true,
+ "deprecated": true
+ },
+ "classify": {
+ "glyph": "⊛",
+ "args": 1,
+ "outputs": 1,
+ "class": "MonadicArray",
+ "description": "Assign a unique index to each unique row in an array"
+ },
+ "complex": {
+ "glyph": "ℂ",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicPervasive",
+ "description": "Make a complex number"
+ },
+ "comptime": {
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "Comptime",
+ "description": "Run a function at compile time"
+ },
+ "content": {
+ "glyph": "◇",
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "OtherModifier",
+ "description": "Unbox the arguments to a function before calling it"
+ },
+ "couple": {
+ "glyph": "⊟",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicArray",
+ "description": "Combine two arrays as rows of a new array"
+ },
+ "csv": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Encoding",
+ "description": "Encode an array into a CSV string"
+ },
+ "datetime": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Misc",
+ "description": "Get the date and time information from a time"
+ },
+ "deduplicate": {
+ "glyph": "◴",
+ "args": 1,
+ "outputs": 1,
+ "class": "MonadicArray",
+ "description": "Remove duplicate rows from an array"
+ },
+ "derivative": {
+ "glyph": "∂",
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "Misc",
+ "description": "Calculate the derivative of a mathematical expression",
+ "experimental": true
+ },
+ "deshape": {
+ "glyph": "♭",
+ "args": 1,
+ "outputs": 1,
+ "class": "MonadicArray",
+ "description": "Make an array 1-dimensional"
+ },
+ "dip": {
+ "glyph": "⊙",
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "Planet",
+ "description": "Temporarily pop the top value off the stack and call a function"
+ },
+ "divide": {
+ "ascii": "%",
+ "glyph": "÷",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicPervasive",
+ "description": "Divide values"
+ },
+ "do": {
+ "glyph": "⍢",
+ "outputs": 1,
+ "modifier_args": 2,
+ "class": "IteratingModifier",
+ "description": "Repeat a function while a condition holds"
+ },
+ "drop": {
+ "glyph": "↘",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicArray",
+ "description": "Drop the first n rows of an array"
+ },
+ "dump": {
+ "args": 0,
+ "outputs": 0,
+ "modifier_args": 1,
+ "class": "Debug",
+ "description": "Preprocess and print all stack values without popping them"
+ },
+ "duplicate": {
+ "glyph": ".",
+ "args": 1,
+ "outputs": 2,
+ "class": "Stack",
+ "description": "Duplicate the top value on the stack"
+ },
+ "each": {
+ "glyph": "∵",
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "IteratingModifier",
+ "description": "Apply a function to each element of an array or arrays"
+ },
+ "equals": {
+ "ascii": "=",
+ "glyph": "=",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicPervasive",
+ "description": "Compare for equality"
+ },
+ "eta": {
+ "glyph": "η",
+ "args": 0,
+ "outputs": 1,
+ "class": "Constant",
+ "description": "The number of radians in a quarter circle"
+ },
+ "eval": {
+ "args": 2,
+ "outputs": 1,
+ "class": "Misc",
+ "description": "Evalute a string as code at compile time",
+ "experimental": true
+ },
+ "fall": {
+ "glyph": "⍖",
+ "args": 1,
+ "outputs": 1,
+ "class": "MonadicArray",
+ "description": "Get the indices into an array if it were sorted descending"
+ },
+ "fft": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Misc",
+ "description": "Run the Fast Fourier Transform on an array",
+ "experimental": true
+ },
+ "fill": {
+ "glyph": "⬚",
+ "outputs": 1,
+ "modifier_args": 2,
+ "class": "OtherModifier",
+ "description": "Set the fill value for a function"
+ },
+ "find": {
+ "glyph": "⌕",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicArray",
+ "description": "Find the occurences of one array in another"
+ },
+ "first": {
+ "glyph": "⊢",
+ "args": 1,
+ "outputs": 1,
+ "class": "MonadicArray",
+ "description": "Get the first row of an array"
+ },
+ "fix": {
+ "glyph": "¤",
+ "args": 1,
+ "outputs": 1,
+ "class": "MonadicArray",
+ "description": "Add a length-1 axis to an array"
+ },
+ "flip": {
+ "ascii": ":",
+ "glyph": ":",
+ "args": 2,
+ "outputs": 2,
+ "class": "Stack",
+ "description": "Swap the top two values on the stack"
+ },
+ "floor": {
+ "glyph": "⌊",
+ "args": 1,
+ "outputs": 1,
+ "class": "MonadicPervasive",
+ "description": "Round to the nearest integer towards ¯∞"
+ },
+ "fold": {
+ "glyph": "∧",
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "AggregatingModifier",
+ "description": "Apply a function to aggregate arrays"
+ },
+ "fork": {
+ "glyph": "⊃",
+ "outputs": 1,
+ "modifier_args": 2,
+ "class": "Planet",
+ "description": "Call two functions on the same values"
+ },
+ "gap": {
+ "glyph": "⋅",
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "Planet",
+ "description": "Discard the top stack value then call a function"
+ },
+ "gen": {
+ "args": 2,
+ "outputs": 1,
+ "class": "Misc",
+ "description": "Generate an array of random numbers with a seed"
+ },
+ "get": {
+ "args": 2,
+ "outputs": 1,
+ "class": "Map",
+ "description": "Get the value corresponding to a key in a map array"
+ },
+ "gif": {
+ "args": 2,
+ "outputs": 1,
+ "class": "Encoding",
+ "description": "Encode a gif into a byte array"
+ },
+ "graphemes": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Encoding",
+ "description": "Convert a string to a list of UTF-8 grapheme clusters"
+ },
+ "greater or equal": {
+ "ascii": ">=",
+ "glyph": "≥",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicPervasive",
+ "description": "Compare for greater than or equal"
+ },
+ "greater than": {
+ "glyph": ">",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicPervasive",
+ "description": "Compare for greater than"
+ },
+ "group": {
+ "glyph": "⊕",
+ "args": 2,
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "AggregatingModifier",
+ "description": "Group elements of an array into buckets by index"
+ },
+ "has": {
+ "args": 2,
+ "outputs": 1,
+ "class": "Map",
+ "description": "Check if a map array has a key"
+ },
+ "identity": {
+ "glyph": "∘",
+ "args": 1,
+ "outputs": 1,
+ "class": "Planet",
+ "description": "Do nothing with one value"
+ },
+ "img": {
+ "args": 2,
+ "outputs": 1,
+ "class": "Encoding",
+ "description": "Encode an image into a byte array with the specified format"
+ },
+ "indexof": {
+ "glyph": "⊗",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicArray",
+ "description": "Find the first index of each row of one array in another"
+ },
+ "infinity": {
+ "glyph": "∞",
+ "args": 0,
+ "outputs": 1,
+ "class": "Constant",
+ "description": "The biggest number"
+ },
+ "insert": {
+ "args": 3,
+ "outputs": 1,
+ "class": "Map",
+ "description": "Insert a key-value pair into a map array"
+ },
+ "integral": {
+ "glyph": "∫",
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "Misc",
+ "description": "Calculate an antiderivative of a mathematical expression",
+ "experimental": true
+ },
+ "inventory": {
+ "glyph": "⍚",
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "IteratingModifier",
+ "description": "Apply a function to each unboxed row of an array and re-box the results"
+ },
+ "join": {
+ "glyph": "⊂",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicArray",
+ "description": "Append two arrays end-to-end"
+ },
+ "json": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Encoding",
+ "description": "Encode an array into a JSON string"
+ },
+ "keep": {
+ "glyph": "▽",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicArray",
+ "description": "Discard or copy some rows of an array"
+ },
+ "last": {
+ "glyph": "⊣",
+ "args": 1,
+ "outputs": 1,
+ "class": "MonadicArray",
+ "description": "Get the last row of an array"
+ },
+ "layout": {
+ "args": 2,
+ "outputs": 1,
+ "class": "Encoding",
+ "description": "Render text into an image array",
+ "experimental": true
+ },
+ "length": {
+ "glyph": "⧻",
+ "args": 1,
+ "outputs": 1,
+ "class": "MonadicArray",
+ "description": "Get the number of rows in an array"
+ },
+ "less or equal": {
+ "ascii": "<=",
+ "glyph": "≤",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicPervasive",
+ "description": "Compare for less than or equal"
+ },
+ "less than": {
+ "glyph": "<",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicPervasive",
+ "description": "Compare for less than"
+ },
+ "logarithm": {
+ "glyph": "ₙ",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicPervasive",
+ "description": "Get the based logarithm of a number"
+ },
+ "map": {
+ "args": 2,
+ "outputs": 1,
+ "class": "Map",
+ "description": "Create a hashmap from a list of keys and list values"
+ },
+ "mask": {
+ "glyph": "⦷",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicArray",
+ "description": "Mask the occurences of one array in another"
+ },
+ "match": {
+ "glyph": "≍",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicArray",
+ "description": "Check if two arrays are exactly the same"
+ },
+ "maximum": {
+ "glyph": "↥",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicPervasive",
+ "description": "Take the maximum of two arrays"
+ },
+ "member": {
+ "glyph": "∊",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicArray",
+ "description": "Check if each row of one array exists in another",
+ "deprecated": true
+ },
+ "memberof": {
+ "glyph": "∈",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicArray",
+ "description": "Check if each row of one array exists in another"
+ },
+ "memo": {
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "OtherModifier",
+ "description": "Memoize a function"
+ },
+ "minimum": {
+ "glyph": "↧",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicPervasive",
+ "description": "Take the minimum of two arrays"
+ },
+ "modulus": {
+ "glyph": "◿",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicPervasive",
+ "description": "Modulo values"
+ },
+ "multiply": {
+ "ascii": "*",
+ "glyph": "×",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicPervasive",
+ "description": "Multiply values"
+ },
+ "negate": {
+ "ascii": "`",
+ "glyph": "¯",
+ "args": 1,
+ "outputs": 1,
+ "class": "MonadicPervasive",
+ "description": "Negate a number"
+ },
+ "not": {
+ "glyph": "¬",
+ "args": 1,
+ "outputs": 1,
+ "class": "MonadicPervasive",
+ "description": "Logical not"
+ },
+ "not equals": {
+ "ascii": "!=",
+ "glyph": "≠",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicPervasive",
+ "description": "Compare for inequality"
+ },
+ "now": {
+ "args": 0,
+ "outputs": 1,
+ "class": "Misc",
+ "description": "Get the current time in seconds"
+ },
+ "obverse": {
+ "glyph": "⌅",
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "InversionModifier",
+ "description": "Define the various inverses of a function"
+ },
+ "off": {
+ "glyph": "⤚",
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "Stack",
+ "description": "Call a function but keep its first argument under the outputs on the stack",
+ "experimental": true
+ },
+ "on": {
+ "glyph": "⟜",
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "Stack",
+ "description": "Call a function but keep its first argument on the top of the stack"
+ },
+ "or": {
+ "glyph": "∨",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicPervasive",
+ "description": "Logical OR and greatest common divisor",
+ "experimental": true
+ },
+ "orient": {
+ "glyph": "⤸",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicArray",
+ "description": "Change the order of the axes of an array"
+ },
+ "over": {
+ "glyph": ",",
+ "args": 2,
+ "outputs": 3,
+ "class": "Stack",
+ "description": "Duplicate the second-to-top value to the top of the stack"
+ },
+ "parse": {
+ "glyph": "⋕",
+ "args": 1,
+ "outputs": 1,
+ "class": "Misc",
+ "description": "Parse a string as a number"
+ },
+ "partition": {
+ "glyph": "⊜",
+ "args": 2,
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "AggregatingModifier",
+ "description": "Group sequential sections of an array"
+ },
+ "permute": {
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicArray",
+ "description": "Get all permutations of k rows from an array",
+ "experimental": true,
+ "deprecated": true
+ },
+ "pi": {
+ "glyph": "π",
+ "args": 0,
+ "outputs": 1,
+ "class": "Constant",
+ "description": "The ratio of a circle's circumference to its diameter"
+ },
+ "pick": {
+ "glyph": "⊡",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicArray",
+ "description": "Index a row or elements from an array"
+ },
+ "pool": {
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "Thread",
+ "description": "Spawn a thread in a thread pool"
+ },
+ "pop": {
+ "glyph": "◌",
+ "args": 1,
+ "outputs": 0,
+ "class": "Stack",
+ "description": "Discard the top stack value"
+ },
+ "power": {
+ "glyph": "ⁿ",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicPervasive",
+ "description": "Raise a value to a power"
+ },
+ "quote": {
+ "args": 0,
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "Comptime",
+ "description": "Convert a string into code at compile time",
+ "experimental": true
+ },
+ "random": {
+ "glyph": "⚂",
+ "args": 0,
+ "outputs": 1,
+ "class": "Misc",
+ "description": "Generate a random number in the range [0, 1)"
+ },
+ "range": {
+ "glyph": "⇡",
+ "args": 1,
+ "outputs": 1,
+ "class": "MonadicArray",
+ "description": "Make an array of all natural numbers less than a number"
+ },
+ "recv": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Thread",
+ "description": "Receive a value from a thread"
+ },
+ "reduce": {
+ "glyph": "/",
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "AggregatingModifier",
+ "description": "Apply a reducing function to an array"
+ },
+ "regex": {
+ "args": 2,
+ "outputs": 1,
+ "class": "Misc",
+ "description": "Match a regex pattern"
+ },
+ "remove": {
+ "args": 2,
+ "outputs": 1,
+ "class": "Map",
+ "description": "Remove the value corresponding to a key from a map array"
+ },
+ "repeat": {
+ "glyph": "⍥",
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "IteratingModifier",
+ "description": "Repeat a function a number of times"
+ },
+ "repr": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Misc",
+ "description": "Convert a value to its code representation"
+ },
+ "rerank": {
+ "glyph": "☇",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicArray",
+ "description": "Change the rank of an array's rows",
+ "deprecated": true
+ },
+ "reshape": {
+ "glyph": "↯",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicArray",
+ "description": "Change the shape of an array"
+ },
+ "reverse": {
+ "glyph": "⇌",
+ "args": 1,
+ "outputs": 1,
+ "class": "MonadicArray",
+ "description": "Reverse the rows of an array"
+ },
+ "rise": {
+ "glyph": "⍏",
+ "args": 1,
+ "outputs": 1,
+ "class": "MonadicArray",
+ "description": "Get the indices into an array if it were sorted ascending"
+ },
+ "rotate": {
+ "glyph": "↻",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicArray",
+ "description": "Rotate the elements of an array by n"
+ },
+ "round": {
+ "glyph": "⁅",
+ "args": 1,
+ "outputs": 1,
+ "class": "MonadicPervasive",
+ "description": "Round to the nearest integer"
+ },
+ "rows": {
+ "glyph": "≡",
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "IteratingModifier",
+ "description": "Apply a function to each row of an array or arrays"
+ },
+ "scan": {
+ "glyph": "\\",
+ "args": 1,
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "AggregatingModifier",
+ "description": "Reduce, but keep intermediate values"
+ },
+ "select": {
+ "glyph": "⊏",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicArray",
+ "description": "Select multiple rows from an array"
+ },
+ "send": {
+ "args": 2,
+ "outputs": 0,
+ "class": "Thread",
+ "description": "Send a value to a thread"
+ },
+ "shape": {
+ "glyph": "△",
+ "args": 1,
+ "outputs": 1,
+ "class": "MonadicArray",
+ "description": "Get the dimensions of an array"
+ },
+ "sign": {
+ "glyph": "±",
+ "args": 1,
+ "outputs": 1,
+ "class": "MonadicPervasive",
+ "description": "Numerical sign (1, ¯1, or 0)"
+ },
+ "signature": {
+ "args": 0,
+ "outputs": 2,
+ "modifier_args": 1,
+ "class": "Comptime",
+ "description": "Get the signature of a function",
+ "experimental": true,
+ "deprecated": true
+ },
+ "sine": {
+ "glyph": "∿",
+ "args": 1,
+ "outputs": 1,
+ "class": "MonadicPervasive",
+ "description": "Get the sine of a number"
+ },
+ "sort": {
+ "glyph": "⍆",
+ "args": 1,
+ "outputs": 1,
+ "class": "MonadicArray",
+ "description": "Sort an array"
+ },
+ "spawn": {
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "Thread",
+ "description": "Spawn a thread"
+ },
+ "sqrt": {
+ "glyph": "√",
+ "args": 1,
+ "outputs": 1,
+ "class": "MonadicPervasive",
+ "description": "Take the square root of a number"
+ },
+ "stack": {
+ "glyph": "?",
+ "args": 0,
+ "outputs": 0,
+ "class": "Debug",
+ "description": "Debug print all stack values without popping them"
+ },
+ "stringify": {
+ "args": 0,
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "Comptime",
+ "description": "Convert code into a string instead of compiling it",
+ "experimental": true,
+ "deprecated": true
+ },
+ "subtract": {
+ "glyph": "-",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicPervasive",
+ "description": "Subtract values"
+ },
+ "switch": {
+ "glyph": "⨬",
+ "outputs": 1,
+ "modifier_args": 2,
+ "class": "OtherModifier",
+ "description": "Call the function at the given index"
+ },
+ "table": {
+ "glyph": "⊞",
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "IteratingModifier",
+ "description": "Apply a function to each combination of rows of some arrays"
+ },
+ "tag": {
+ "args": 0,
+ "outputs": 1,
+ "class": "Misc",
+ "description": "Generate a unique tag"
+ },
+ "take": {
+ "glyph": "↙",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicArray",
+ "description": "Take the first n rows of an array"
+ },
+ "tau": {
+ "glyph": "τ",
+ "args": 0,
+ "outputs": 1,
+ "class": "Constant",
+ "description": "The ratio of a circle's circumference to its radius"
+ },
+ "timezone": {
+ "args": 0,
+ "outputs": 1,
+ "class": "Misc",
+ "description": "Get the local timezone offset"
+ },
+ "trace": {
+ "glyph": "⸮",
+ "args": 1,
+ "outputs": 1,
+ "class": "Debug",
+ "description": "Debug print the top value on the stack without popping it",
+ "deprecated": true
+ },
+ "transpose": {
+ "glyph": "⍉",
+ "args": 1,
+ "outputs": 1,
+ "class": "MonadicArray",
+ "description": "Rotate the shape of an array"
+ },
+ "triangle": {
+ "glyph": "◹",
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "AggregatingModifier",
+ "description": "Apply a function to each shrinking row of an array",
+ "experimental": true,
+ "deprecated": true
+ },
+ "try": {
+ "glyph": "⍣",
+ "outputs": 1,
+ "modifier_args": 2,
+ "class": "Misc",
+ "description": "Call a function and catch errors"
+ },
+ "tryrecv": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Thread",
+ "description": "Try to receive a value from a thread"
+ },
+ "tuples": {
+ "glyph": "⧅",
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "IteratingModifier",
+ "description": "Get permutations or combinations of an array",
+ "experimental": true
+ },
+ "type": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Misc",
+ "description": "Check the type of an array"
+ },
+ "un": {
+ "glyph": "°",
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "InversionModifier",
+ "description": "Invert the behavior of a function"
+ },
+ "under": {
+ "glyph": "⍜",
+ "outputs": 1,
+ "modifier_args": 2,
+ "class": "InversionModifier",
+ "description": "Operate on a transformed array, then reverse the transformation"
+ },
+ "unique": {
+ "glyph": "◰",
+ "args": 1,
+ "outputs": 1,
+ "class": "MonadicArray",
+ "description": "Get a mask of first occurrences of items in an array"
+ },
+ "utf₈": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Encoding",
+ "description": "Convert a string to UTF-8 bytes"
+ },
+ "wait": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Thread",
+ "description": "Wait for a thread to finish and push its results to the stack"
+ },
+ "where": {
+ "glyph": "⊚",
+ "args": 1,
+ "outputs": 1,
+ "class": "MonadicArray",
+ "description": "Get indices where array values are not equal to zero"
+ },
+ "windows": {
+ "glyph": "◫",
+ "args": 2,
+ "outputs": 1,
+ "class": "DyadicArray",
+ "description": "The n-wise windows of an array"
+ },
+ "with": {
+ "glyph": "⤙",
+ "outputs": 1,
+ "modifier_args": 1,
+ "class": "Stack",
+ "description": "Call a function but keep its last argument on the top of the stack"
+ },
+ "xlsx": {
+ "args": 1,
+ "outputs": 1,
+ "class": "Encoding",
+ "description": "Encode an array into XLSX bytes"
+ }
+}
\ No newline at end of file
diff --git a/docs/site-2c10351283036f17.js b/docs/site-2c10351283036f17.js
new file mode 100644
index 000000000..0080ec78a
--- /dev/null
+++ b/docs/site-2c10351283036f17.js
@@ -0,0 +1,1711 @@
+let wasm;
+
+const heap = new Array(128).fill(undefined);
+
+heap.push(undefined, null, true, false);
+
+function getObject(idx) { return heap[idx]; }
+
+let heap_next = heap.length;
+
+function dropObject(idx) {
+ if (idx < 132) return;
+ heap[idx] = heap_next;
+ heap_next = idx;
+}
+
+function takeObject(idx) {
+ const ret = getObject(idx);
+ dropObject(idx);
+ return ret;
+}
+
+function addHeapObject(obj) {
+ if (heap_next === heap.length) heap.push(heap.length + 1);
+ const idx = heap_next;
+ heap_next = heap[idx];
+
+ heap[idx] = obj;
+ return idx;
+}
+
+const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } );
+
+if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); };
+
+let cachedUint8ArrayMemory0 = null;
+
+function getUint8ArrayMemory0() {
+ if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
+ cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
+ }
+ return cachedUint8ArrayMemory0;
+}
+
+function getStringFromWasm0(ptr, len) {
+ ptr = ptr >>> 0;
+ return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
+}
+
+let WASM_VECTOR_LEN = 0;
+
+const cachedTextEncoder = (typeof TextEncoder !== 'undefined' ? new TextEncoder('utf-8') : { encode: () => { throw Error('TextEncoder not available') } } );
+
+const encodeString = (typeof cachedTextEncoder.encodeInto === 'function'
+ ? function (arg, view) {
+ return cachedTextEncoder.encodeInto(arg, view);
+}
+ : function (arg, view) {
+ const buf = cachedTextEncoder.encode(arg);
+ view.set(buf);
+ return {
+ read: arg.length,
+ written: buf.length
+ };
+});
+
+function passStringToWasm0(arg, malloc, realloc) {
+
+ if (realloc === undefined) {
+ const buf = cachedTextEncoder.encode(arg);
+ const ptr = malloc(buf.length, 1) >>> 0;
+ getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
+ WASM_VECTOR_LEN = buf.length;
+ return ptr;
+ }
+
+ let len = arg.length;
+ let ptr = malloc(len, 1) >>> 0;
+
+ const mem = getUint8ArrayMemory0();
+
+ let offset = 0;
+
+ for (; offset < len; offset++) {
+ const code = arg.charCodeAt(offset);
+ if (code > 0x7F) break;
+ mem[ptr + offset] = code;
+ }
+
+ if (offset !== len) {
+ if (offset !== 0) {
+ arg = arg.slice(offset);
+ }
+ ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
+ const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
+ const ret = encodeString(arg, view);
+
+ offset += ret.written;
+ ptr = realloc(ptr, len, offset, 1) >>> 0;
+ }
+
+ WASM_VECTOR_LEN = offset;
+ return ptr;
+}
+
+function isLikeNone(x) {
+ return x === undefined || x === null;
+}
+
+let cachedDataViewMemory0 = null;
+
+function getDataViewMemory0() {
+ if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
+ cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
+ }
+ return cachedDataViewMemory0;
+}
+
+function debugString(val) {
+ // primitive types
+ const type = typeof val;
+ if (type == 'number' || type == 'boolean' || val == null) {
+ return `${val}`;
+ }
+ if (type == 'string') {
+ return `"${val}"`;
+ }
+ if (type == 'symbol') {
+ const description = val.description;
+ if (description == null) {
+ return 'Symbol';
+ } else {
+ return `Symbol(${description})`;
+ }
+ }
+ if (type == 'function') {
+ const name = val.name;
+ if (typeof name == 'string' && name.length > 0) {
+ return `Function(${name})`;
+ } else {
+ return 'Function';
+ }
+ }
+ // objects
+ if (Array.isArray(val)) {
+ const length = val.length;
+ let debug = '[';
+ if (length > 0) {
+ debug += debugString(val[0]);
+ }
+ for(let i = 1; i < length; i++) {
+ debug += ', ' + debugString(val[i]);
+ }
+ debug += ']';
+ return debug;
+ }
+ // Test for built-in
+ const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val));
+ let className;
+ if (builtInMatches.length > 1) {
+ className = builtInMatches[1];
+ } else {
+ // Failed to match the standard '[object ClassName]'
+ return toString.call(val);
+ }
+ if (className == 'Object') {
+ // we're a user defined class or Object
+ // JSON.stringify avoids problems with cycles, and is generally much
+ // easier than looping through ownProperties of `val`.
+ try {
+ return 'Object(' + JSON.stringify(val) + ')';
+ } catch (_) {
+ return 'Object';
+ }
+ }
+ // errors
+ if (val instanceof Error) {
+ return `${val.name}: ${val.message}\n${val.stack}`;
+ }
+ // TODO we could test for more things here, like `Set`s and `Map`s.
+ return className;
+}
+
+const CLOSURE_DTORS = (typeof FinalizationRegistry === 'undefined')
+ ? { register: () => {}, unregister: () => {} }
+ : new FinalizationRegistry(state => {
+ wasm.__wbindgen_export_2.get(state.dtor)(state.a, state.b)
+});
+
+function makeMutClosure(arg0, arg1, dtor, f) {
+ const state = { a: arg0, b: arg1, cnt: 1, dtor };
+ const real = (...args) => {
+ // First up with a closure we increment the internal reference
+ // count. This ensures that the Rust closure environment won't
+ // be deallocated while we're invoking it.
+ state.cnt++;
+ const a = state.a;
+ state.a = 0;
+ try {
+ return f(a, state.b, ...args);
+ } finally {
+ if (--state.cnt === 0) {
+ wasm.__wbindgen_export_2.get(state.dtor)(a, state.b);
+ CLOSURE_DTORS.unregister(state);
+ } else {
+ state.a = a;
+ }
+ }
+ };
+ real.original = state;
+ CLOSURE_DTORS.register(real, state, state);
+ return real;
+}
+function __wbg_adapter_38(arg0, arg1, arg2) {
+ wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h47b7a0b6f91c419d(arg0, arg1, addHeapObject(arg2));
+}
+
+function __wbg_adapter_41(arg0, arg1, arg2) {
+ wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h8d4d76623dd0e609(arg0, arg1, addHeapObject(arg2));
+}
+
+function __wbg_adapter_44(arg0, arg1) {
+ wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h9125f222268dcdfb(arg0, arg1);
+}
+
+function __wbg_adapter_47(arg0, arg1, arg2) {
+ wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hb27808f873bb2fc0(arg0, arg1, addHeapObject(arg2));
+}
+
+function getCachedStringFromWasm0(ptr, len) {
+ if (ptr === 0) {
+ return getObject(len);
+ } else {
+ return getStringFromWasm0(ptr, len);
+ }
+}
+
+function handleError(f, args) {
+ try {
+ return f.apply(this, args);
+ } catch (e) {
+ wasm.__wbindgen_exn_store(addHeapObject(e));
+ }
+}
+function __wbg_adapter_470(arg0, arg1, arg2, arg3) {
+ wasm.wasm_bindgen__convert__closures__invoke2_mut__h5bde19052f186a2b(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3));
+}
+
+const IntoUnderlyingByteSourceFinalization = (typeof FinalizationRegistry === 'undefined')
+ ? { register: () => {}, unregister: () => {} }
+ : new FinalizationRegistry(ptr => wasm.__wbg_intounderlyingbytesource_free(ptr >>> 0, 1));
+/**
+*/
+export class IntoUnderlyingByteSource {
+
+ __destroy_into_raw() {
+ const ptr = this.__wbg_ptr;
+ this.__wbg_ptr = 0;
+ IntoUnderlyingByteSourceFinalization.unregister(this);
+ return ptr;
+ }
+
+ free() {
+ const ptr = this.__destroy_into_raw();
+ wasm.__wbg_intounderlyingbytesource_free(ptr, 0);
+ }
+ /**
+ * @returns {string}
+ */
+ get type() {
+ try {
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
+ wasm.intounderlyingbytesource_type(retptr, this.__wbg_ptr);
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
+ var v1 = getCachedStringFromWasm0(r0, r1);
+ if (r0 !== 0) { wasm.__wbindgen_free(r0, r1, 1); }
+ return v1;
+ } finally {
+ wasm.__wbindgen_add_to_stack_pointer(16);
+ }
+}
+/**
+* @returns {number}
+*/
+get autoAllocateChunkSize() {
+ const ret = wasm.intounderlyingbytesource_autoAllocateChunkSize(this.__wbg_ptr);
+ return ret >>> 0;
+}
+/**
+* @param {ReadableByteStreamController} controller
+*/
+start(controller) {
+ wasm.intounderlyingbytesource_start(this.__wbg_ptr, addHeapObject(controller));
+}
+/**
+* @param {ReadableByteStreamController} controller
+* @returns {Promise}
+*/
+pull(controller) {
+ const ret = wasm.intounderlyingbytesource_pull(this.__wbg_ptr, addHeapObject(controller));
+ return takeObject(ret);
+}
+/**
+*/
+cancel() {
+ const ptr = this.__destroy_into_raw();
+ wasm.intounderlyingbytesource_cancel(ptr);
+}
+}
+
+const IntoUnderlyingSinkFinalization = (typeof FinalizationRegistry === 'undefined')
+ ? { register: () => {}, unregister: () => {} }
+ : new FinalizationRegistry(ptr => wasm.__wbg_intounderlyingsink_free(ptr >>> 0, 1));
+/**
+*/
+export class IntoUnderlyingSink {
+
+ __destroy_into_raw() {
+ const ptr = this.__wbg_ptr;
+ this.__wbg_ptr = 0;
+ IntoUnderlyingSinkFinalization.unregister(this);
+ return ptr;
+ }
+
+ free() {
+ const ptr = this.__destroy_into_raw();
+ wasm.__wbg_intounderlyingsink_free(ptr, 0);
+ }
+ /**
+ * @param {any} chunk
+ * @returns {Promise}
+ */
+ write(chunk) {
+ const ret = wasm.intounderlyingsink_write(this.__wbg_ptr, addHeapObject(chunk));
+ return takeObject(ret);
+ }
+ /**
+ * @returns {Promise}
+ */
+ close() {
+ const ptr = this.__destroy_into_raw();
+ const ret = wasm.intounderlyingsink_close(ptr);
+ return takeObject(ret);
+ }
+ /**
+ * @param {any} reason
+ * @returns {Promise}
+ */
+ abort(reason) {
+ const ptr = this.__destroy_into_raw();
+ const ret = wasm.intounderlyingsink_abort(ptr, addHeapObject(reason));
+ return takeObject(ret);
+ }
+}
+
+const IntoUnderlyingSourceFinalization = (typeof FinalizationRegistry === 'undefined')
+ ? { register: () => {}, unregister: () => {} }
+ : new FinalizationRegistry(ptr => wasm.__wbg_intounderlyingsource_free(ptr >>> 0, 1));
+/**
+*/
+export class IntoUnderlyingSource {
+
+ __destroy_into_raw() {
+ const ptr = this.__wbg_ptr;
+ this.__wbg_ptr = 0;
+ IntoUnderlyingSourceFinalization.unregister(this);
+ return ptr;
+ }
+
+ free() {
+ const ptr = this.__destroy_into_raw();
+ wasm.__wbg_intounderlyingsource_free(ptr, 0);
+ }
+ /**
+ * @param {ReadableStreamDefaultController} controller
+ * @returns {Promise}
+ */
+ pull(controller) {
+ const ret = wasm.intounderlyingsource_pull(this.__wbg_ptr, addHeapObject(controller));
+ return takeObject(ret);
+ }
+ /**
+ */
+ cancel() {
+ const ptr = this.__destroy_into_raw();
+ wasm.intounderlyingsource_cancel(ptr);
+ }
+}
+
+async function __wbg_load(module, imports) {
+ if (typeof Response === 'function' && module instanceof Response) {
+ if (typeof WebAssembly.instantiateStreaming === 'function') {
+ try {
+ return await WebAssembly.instantiateStreaming(module, imports);
+
+ } catch (e) {
+ if (module.headers.get('Content-Type') != 'application/wasm') {
+ console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
+
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ const bytes = await module.arrayBuffer();
+ return await WebAssembly.instantiate(bytes, imports);
+
+ } else {
+ const instance = await WebAssembly.instantiate(module, imports);
+
+ if (instance instanceof WebAssembly.Instance) {
+ return { instance, module };
+
+ } else {
+ return instance;
+ }
+ }
+}
+
+function __wbg_get_imports() {
+ const imports = {};
+ imports.wbg = {};
+ imports.wbg.__wbindgen_object_drop_ref = function(arg0) {
+ takeObject(arg0);
+ };
+ imports.wbg.__wbindgen_object_clone_ref = function(arg0) {
+ const ret = getObject(arg0);
+ return addHeapObject(ret);
+ };
+ imports.wbg.__wbindgen_string_new = function(arg0, arg1) {
+ const ret = getStringFromWasm0(arg0, arg1);
+ return addHeapObject(ret);
+ };
+ imports.wbg.__wbindgen_string_get = function(arg0, arg1) {
+ const obj = getObject(arg1);
+ const ret = typeof(obj) === 'string' ? obj : undefined;
+ var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ var len1 = WASM_VECTOR_LEN;
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
+ };
+ imports.wbg.__wbg_new_abda76e883ba8a5f = function() {
+ const ret = new Error();
+ return addHeapObject(ret);
+ };
+ imports.wbg.__wbg_stack_658279fe44541cf6 = function(arg0, arg1) {
+ const ret = getObject(arg1).stack;
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
+ };
+ imports.wbg.__wbg_error_f851667af71bcfc6 = function(arg0, arg1) {
+ var v0 = getCachedStringFromWasm0(arg0, arg1);
+ if (arg0 !== 0) { wasm.__wbindgen_free(arg0, arg1, 1); }
+ console.error(v0);
+};
+imports.wbg.__wbindgen_is_object = function(arg0) {
+ const val = getObject(arg0);
+ const ret = typeof(val) === 'object' && val !== null;
+ return ret;
+};
+imports.wbg.__wbg_crypto_d05b68a3572bb8ca = function(arg0) {
+ const ret = getObject(arg0).crypto;
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_process_b02b3570280d0366 = function(arg0) {
+ const ret = getObject(arg0).process;
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_versions_c1cb42213cedf0f5 = function(arg0) {
+ const ret = getObject(arg0).versions;
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_node_43b1089f407e4ec2 = function(arg0) {
+ const ret = getObject(arg0).node;
+ return addHeapObject(ret);
+};
+imports.wbg.__wbindgen_is_string = function(arg0) {
+ const ret = typeof(getObject(arg0)) === 'string';
+ return ret;
+};
+imports.wbg.__wbg_require_9a7e0f667ead4995 = function() { return handleError(function () {
+ const ret = module.require;
+ return addHeapObject(ret);
+}, arguments) };
+imports.wbg.__wbg_msCrypto_10fc94afee92bd76 = function(arg0) {
+ const ret = getObject(arg0).msCrypto;
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_randomFillSync_b70ccbdf4926a99d = function() { return handleError(function (arg0, arg1) {
+ getObject(arg0).randomFillSync(takeObject(arg1));
+}, arguments) };
+imports.wbg.__wbg_getRandomValues_7e42b4fb8779dc6d = function() { return handleError(function (arg0, arg1) {
+ getObject(arg0).getRandomValues(getObject(arg1));
+}, arguments) };
+imports.wbg.__wbindgen_jsval_eq = function(arg0, arg1) {
+ const ret = getObject(arg0) === getObject(arg1);
+ return ret;
+};
+imports.wbg.__wbindgen_boolean_get = function(arg0) {
+ const v = getObject(arg0);
+ const ret = typeof(v) === 'boolean' ? (v ? 1 : 0) : 2;
+ return ret;
+};
+imports.wbg.__wbindgen_is_undefined = function(arg0) {
+ const ret = getObject(arg0) === undefined;
+ return ret;
+};
+imports.wbg.__wbindgen_number_get = function(arg0, arg1) {
+ const obj = getObject(arg1);
+ const ret = typeof(obj) === 'number' ? obj : undefined;
+ getDataViewMemory0().setFloat64(arg0 + 8 * 1, isLikeNone(ret) ? 0 : ret, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, !isLikeNone(ret), true);
+};
+imports.wbg.__wbindgen_is_null = function(arg0) {
+ const ret = getObject(arg0) === null;
+ return ret;
+};
+imports.wbg.__wbindgen_is_falsy = function(arg0) {
+ const ret = !getObject(arg0);
+ return ret;
+};
+imports.wbg.__wbindgen_cb_drop = function(arg0) {
+ const obj = takeObject(arg0).original;
+ if (obj.cnt-- == 1) {
+ obj.a = 0;
+ return true;
+ }
+ const ret = false;
+ return ret;
+};
+imports.wbg.__wbg_instanceof_Window_5012736c80a01584 = function(arg0) {
+ let result;
+ try {
+ result = getObject(arg0) instanceof Window;
+ } catch (_) {
+ result = false;
+ }
+ const ret = result;
+ return ret;
+};
+imports.wbg.__wbg_document_8554450897a855b9 = function(arg0) {
+ const ret = getObject(arg0).document;
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
+};
+imports.wbg.__wbg_location_af118da6c50d4c3f = function(arg0) {
+ const ret = getObject(arg0).location;
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_history_489e13d0b625263c = function() { return handleError(function (arg0) {
+ const ret = getObject(arg0).history;
+ return addHeapObject(ret);
+}, arguments) };
+imports.wbg.__wbg_navigator_6210380287bf8581 = function(arg0) {
+ const ret = getObject(arg0).navigator;
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_localStorage_90db5cb66e840248 = function() { return handleError(function (arg0) {
+ const ret = getObject(arg0).localStorage;
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
+}, arguments) };
+imports.wbg.__wbg_getComputedStyle_ba4609b39055f674 = function() { return handleError(function (arg0, arg1) {
+ const ret = getObject(arg0).getComputedStyle(getObject(arg1));
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
+}, arguments) };
+imports.wbg.__wbg_open_43b3c6577af2a808 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
+ var v0 = getCachedStringFromWasm0(arg1, arg2);
+ var v1 = getCachedStringFromWasm0(arg3, arg4);
+ const ret = getObject(arg0).open(v0, v1);
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
+}, arguments) };
+imports.wbg.__wbg_prompt_8fdcc5597c730ad8 = function() { return handleError(function (arg0, arg1, arg2, arg3) {
+ var v0 = getCachedStringFromWasm0(arg2, arg3);
+ const ret = getObject(arg1).prompt(v0);
+ var ptr2 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ var len2 = WASM_VECTOR_LEN;
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len2, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr2, true);
+}, arguments) };
+imports.wbg.__wbg_scrollTo_19dc1dbbc8c19fa8 = function(arg0, arg1, arg2) {
+ getObject(arg0).scrollTo(arg1, arg2);
+};
+imports.wbg.__wbg_requestAnimationFrame_b4b782250b9c2c88 = function() { return handleError(function (arg0, arg1) {
+ const ret = getObject(arg0).requestAnimationFrame(getObject(arg1));
+ return ret;
+}, arguments) };
+imports.wbg.__wbg_fetch_f3adf866d8944b41 = function(arg0, arg1) {
+ const ret = getObject(arg0).fetch(getObject(arg1));
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_setTimeout_73b734ca971c19f4 = function() { return handleError(function (arg0, arg1, arg2) {
+ const ret = getObject(arg0).setTimeout(getObject(arg1), arg2);
+ return ret;
+}, arguments) };
+imports.wbg.__wbg_settitle_64405a7dab688b2b = function(arg0, arg1, arg2) {
+ var v0 = getCachedStringFromWasm0(arg1, arg2);
+ getObject(arg0).title = v0;
+};
+imports.wbg.__wbg_body_b3bb488e8e54bf4b = function(arg0) {
+ const ret = getObject(arg0).body;
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
+};
+imports.wbg.__wbg_head_6c6317d70f23ff16 = function(arg0) {
+ const ret = getObject(arg0).head;
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
+};
+imports.wbg.__wbg_createComment_7a1d9856e50567bb = function(arg0, arg1, arg2) {
+ var v0 = getCachedStringFromWasm0(arg1, arg2);
+ const ret = getObject(arg0).createComment(v0);
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_createDocumentFragment_5d919bd9d2e05b55 = function(arg0) {
+ const ret = getObject(arg0).createDocumentFragment();
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_createElement_5921e9eb06b9ec89 = function() { return handleError(function (arg0, arg1, arg2) {
+ var v0 = getCachedStringFromWasm0(arg1, arg2);
+ const ret = getObject(arg0).createElement(v0);
+ return addHeapObject(ret);
+}, arguments) };
+imports.wbg.__wbg_createTextNode_8bce33cf33bf8f6e = function(arg0, arg1, arg2) {
+ var v0 = getCachedStringFromWasm0(arg1, arg2);
+ const ret = getObject(arg0).createTextNode(v0);
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_getElementById_f56c8e6a15a6926d = function(arg0, arg1, arg2) {
+ var v0 = getCachedStringFromWasm0(arg1, arg2);
+ const ret = getObject(arg0).getElementById(v0);
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
+};
+imports.wbg.__wbg_querySelector_e21c39150aa72078 = function() { return handleError(function (arg0, arg1, arg2) {
+ var v0 = getCachedStringFromWasm0(arg1, arg2);
+ const ret = getObject(arg0).querySelector(v0);
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
+}, arguments) };
+imports.wbg.__wbg_instanceof_Element_cc034878d52a64fa = function(arg0) {
+ let result;
+ try {
+ result = getObject(arg0) instanceof Element;
+ } catch (_) {
+ result = false;
+ }
+ const ret = result;
+ return ret;
+};
+imports.wbg.__wbg_id_8071f78aa2301217 = function(arg0, arg1) {
+ const ret = getObject(arg1).id;
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
+};
+imports.wbg.__wbg_setclassName_972f4bd6262f9c17 = function(arg0, arg1, arg2) {
+ var v0 = getCachedStringFromWasm0(arg1, arg2);
+ getObject(arg0).className = v0;
+};
+imports.wbg.__wbg_classList_d725bcb3b32c27b5 = function(arg0) {
+ const ret = getObject(arg0).classList;
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_setscrollLeft_ea3bf3bd376dd783 = function(arg0, arg1) {
+ getObject(arg0).scrollLeft = arg1;
+};
+imports.wbg.__wbg_scrollWidth_a2bdee78f09b4be7 = function(arg0) {
+ const ret = getObject(arg0).scrollWidth;
+ return ret;
+};
+imports.wbg.__wbg_setinnerHTML_ea7e3c6a3c4790c6 = function(arg0, arg1, arg2) {
+ var v0 = getCachedStringFromWasm0(arg1, arg2);
+ getObject(arg0).innerHTML = v0;
+};
+imports.wbg.__wbg_children_0725d024369e02df = function(arg0) {
+ const ret = getObject(arg0).children;
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_getAttribute_e867e037f066c410 = function(arg0, arg1, arg2, arg3) {
+ var v0 = getCachedStringFromWasm0(arg2, arg3);
+ const ret = getObject(arg1).getAttribute(v0);
+ var ptr2 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ var len2 = WASM_VECTOR_LEN;
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len2, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr2, true);
+};
+imports.wbg.__wbg_getBoundingClientRect_35fc4d8fa10e0463 = function(arg0) {
+ const ret = getObject(arg0).getBoundingClientRect();
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_getElementsByTagName_2a045f6645eead77 = function(arg0, arg1, arg2) {
+ var v0 = getCachedStringFromWasm0(arg1, arg2);
+ const ret = getObject(arg0).getElementsByTagName(v0);
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_hasAttribute_a17d49194d050f19 = function(arg0, arg1, arg2) {
+ var v0 = getCachedStringFromWasm0(arg1, arg2);
+ const ret = getObject(arg0).hasAttribute(v0);
+ return ret;
+};
+imports.wbg.__wbg_removeAttribute_c80e298b60689065 = function() { return handleError(function (arg0, arg1, arg2) {
+ var v0 = getCachedStringFromWasm0(arg1, arg2);
+ getObject(arg0).removeAttribute(v0);
+}, arguments) };
+imports.wbg.__wbg_scrollIntoView_4b805e2532108e71 = function(arg0) {
+ getObject(arg0).scrollIntoView();
+};
+imports.wbg.__wbg_scrollIntoView_569698f4895545a5 = function(arg0, arg1) {
+ getObject(arg0).scrollIntoView(getObject(arg1));
+};
+imports.wbg.__wbg_setAttribute_d5540a19be09f8dc = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
+ var v0 = getCachedStringFromWasm0(arg1, arg2);
+ var v1 = getCachedStringFromWasm0(arg3, arg4);
+ getObject(arg0).setAttribute(v0, v1);
+}, arguments) };
+imports.wbg.__wbg_before_ac3792b457802cbf = function() { return handleError(function (arg0, arg1) {
+ getObject(arg0).before(getObject(arg1));
+}, arguments) };
+imports.wbg.__wbg_remove_5b68b70c39041e2a = function(arg0) {
+ getObject(arg0).remove();
+};
+imports.wbg.__wbg_add_e210e3b838bff57f = function() { return handleError(function (arg0, arg1, arg2) {
+ var v0 = getCachedStringFromWasm0(arg1, arg2);
+ getObject(arg0).add(v0);
+}, arguments) };
+imports.wbg.__wbg_remove_0dd2beafdaa4d9ba = function() { return handleError(function (arg0, arg1, arg2) {
+ var v0 = getCachedStringFromWasm0(arg1, arg2);
+ getObject(arg0).remove(v0);
+}, arguments) };
+imports.wbg.__wbg_name_ed3cda975cce080d = function(arg0, arg1) {
+ const ret = getObject(arg1).name;
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
+};
+imports.wbg.__wbg_length_f2469772b8ec9ea3 = function(arg0) {
+ const ret = getObject(arg0).length;
+ return ret;
+};
+imports.wbg.__wbg_get_6d8ff52d2078d871 = function(arg0, arg1) {
+ const ret = getObject(arg0)[arg1 >>> 0];
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
+};
+imports.wbg.__wbg_play_69733added0ad2db = function() { return handleError(function (arg0) {
+ const ret = getObject(arg0).play();
+ return addHeapObject(ret);
+}, arguments) };
+imports.wbg.__wbg_now_a69647afb1f66247 = function(arg0) {
+ const ret = getObject(arg0).now();
+ return ret;
+};
+imports.wbg.__wbg_getPropertyValue_b0f0858c3b5f17dd = function() { return handleError(function (arg0, arg1, arg2, arg3) {
+ var v0 = getCachedStringFromWasm0(arg2, arg3);
+ const ret = getObject(arg1).getPropertyValue(v0);
+ const ptr2 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len2 = WASM_VECTOR_LEN;
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len2, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr2, true);
+}, arguments) };
+imports.wbg.__wbg_removeProperty_cfd836a4f7e5e86e = function() { return handleError(function (arg0, arg1, arg2, arg3) {
+ var v0 = getCachedStringFromWasm0(arg2, arg3);
+ const ret = getObject(arg1).removeProperty(v0);
+ const ptr2 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len2 = WASM_VECTOR_LEN;
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len2, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr2, true);
+}, arguments) };
+imports.wbg.__wbg_setProperty_ff389e5a7fb9910e = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
+ var v0 = getCachedStringFromWasm0(arg1, arg2);
+ var v1 = getCachedStringFromWasm0(arg3, arg4);
+ getObject(arg0).setProperty(v0, v1);
+}, arguments) };
+imports.wbg.__wbg_instanceof_HtmlTextAreaElement_75bfdd55ca1a4a97 = function(arg0) {
+ let result;
+ try {
+ result = getObject(arg0) instanceof HTMLTextAreaElement;
+ } catch (_) {
+ result = false;
+ }
+ const ret = result;
+ return ret;
+};
+imports.wbg.__wbg_value_2bde81aca5570118 = function(arg0, arg1) {
+ const ret = getObject(arg1).value;
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
+};
+imports.wbg.__wbg_setvalue_5b6537234b7d08ee = function(arg0, arg1, arg2) {
+ var v0 = getCachedStringFromWasm0(arg1, arg2);
+ getObject(arg0).value = v0;
+};
+imports.wbg.__wbg_selectionStart_2dc3d6141239a7a2 = function() { return handleError(function (arg0, arg1) {
+ const ret = getObject(arg1).selectionStart;
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, isLikeNone(ret) ? 0 : ret, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, !isLikeNone(ret), true);
+}, arguments) };
+imports.wbg.__wbg_selectionEnd_de210773370d6364 = function() { return handleError(function (arg0, arg1) {
+ const ret = getObject(arg1).selectionEnd;
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, isLikeNone(ret) ? 0 : ret, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, !isLikeNone(ret), true);
+}, arguments) };
+imports.wbg.__wbg_setSelectionRange_2aa3c241274cbc2f = function() { return handleError(function (arg0, arg1, arg2) {
+ getObject(arg0).setSelectionRange(arg1 >>> 0, arg2 >>> 0);
+}, arguments) };
+imports.wbg.__wbg_byobRequest_b32c77640da946ac = function(arg0) {
+ const ret = getObject(arg0).byobRequest;
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
+};
+imports.wbg.__wbg_close_aca7442e6619206b = function() { return handleError(function (arg0) {
+ getObject(arg0).close();
+}, arguments) };
+imports.wbg.__wbg_setbehavior_689064979b5313ca = function(arg0, arg1) {
+ getObject(arg0).behavior = ["auto","instant","smooth",][arg1];
+};
+imports.wbg.__wbg_href_f1d20018a97415a0 = function(arg0, arg1) {
+ const ret = getObject(arg1).href;
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
+};
+imports.wbg.__wbg_origin_b1cdab9cfa04b734 = function(arg0, arg1) {
+ const ret = getObject(arg1).origin;
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
+};
+imports.wbg.__wbg_pathname_adec1eb7f76356a8 = function(arg0, arg1) {
+ const ret = getObject(arg1).pathname;
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
+};
+imports.wbg.__wbg_search_f384756d8e27fd66 = function(arg0, arg1) {
+ const ret = getObject(arg1).search;
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
+};
+imports.wbg.__wbg_searchParams_8b40e0942f870b44 = function(arg0) {
+ const ret = getObject(arg0).searchParams;
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_hash_50828fbc16613897 = function(arg0, arg1) {
+ const ret = getObject(arg1).hash;
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
+};
+imports.wbg.__wbg_newwithbase_ba5e3790a41efd02 = function() { return handleError(function (arg0, arg1, arg2, arg3) {
+ var v0 = getCachedStringFromWasm0(arg0, arg1);
+ var v1 = getCachedStringFromWasm0(arg2, arg3);
+ const ret = new URL(v0, v1);
+ return addHeapObject(ret);
+}, arguments) };
+imports.wbg.__wbg_clipboard_0d7b5c390c14b0e6 = function(arg0) {
+ const ret = getObject(arg0).clipboard;
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_userAgent_58dedff4303aeb66 = function() { return handleError(function (arg0, arg1) {
+ const ret = getObject(arg1).userAgent;
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
+}, arguments) };
+imports.wbg.__wbg_newwithstrandinit_a31c69e4cc337183 = function() { return handleError(function (arg0, arg1, arg2) {
+ var v0 = getCachedStringFromWasm0(arg0, arg1);
+ const ret = new Request(v0, getObject(arg2));
+ return addHeapObject(ret);
+}, arguments) };
+imports.wbg.__wbg_setmethod_dc68a742c2db5c6a = function(arg0, arg1, arg2) {
+ var v0 = getCachedStringFromWasm0(arg1, arg2);
+ getObject(arg0).method = v0;
+};
+imports.wbg.__wbg_setmode_a781aae2bd3df202 = function(arg0, arg1) {
+ getObject(arg0).mode = ["same-origin","no-cors","cors","navigate",][arg1];
+};
+imports.wbg.__wbg_instanceof_Response_e91b7eb7c611a9ae = function(arg0) {
+ let result;
+ try {
+ result = getObject(arg0) instanceof Response;
+ } catch (_) {
+ result = false;
+ }
+ const ret = result;
+ return ret;
+};
+imports.wbg.__wbg_status_ae8de515694c5c7c = function(arg0) {
+ const ret = getObject(arg0).status;
+ return ret;
+};
+imports.wbg.__wbg_text_a94b91ea8700357a = function() { return handleError(function (arg0) {
+ const ret = getObject(arg0).text();
+ return addHeapObject(ret);
+}, arguments) };
+imports.wbg.__wbg_files_a4b6a9811697ac84 = function(arg0) {
+ const ret = getObject(arg0).files;
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
+};
+imports.wbg.__wbg_getData_b768ea3ff59e2a13 = function() { return handleError(function (arg0, arg1, arg2, arg3) {
+ var v0 = getCachedStringFromWasm0(arg2, arg3);
+ const ret = getObject(arg1).getData(v0);
+ const ptr2 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len2 = WASM_VECTOR_LEN;
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len2, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr2, true);
+}, arguments) };
+imports.wbg.__wbg_setbubbles_3fd649bf0421c5ad = function(arg0, arg1) {
+ getObject(arg0).bubbles = arg1 !== 0;
+};
+imports.wbg.__wbg_instanceof_HtmlInputElement_88bf515ab1d9511d = function(arg0) {
+ let result;
+ try {
+ result = getObject(arg0) instanceof HTMLInputElement;
+ } catch (_) {
+ result = false;
+ }
+ const ret = result;
+ return ret;
+};
+imports.wbg.__wbg_files_b94d8f21e2b53924 = function(arg0) {
+ const ret = getObject(arg0).files;
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
+};
+imports.wbg.__wbg_value_d4a95e7a0d390578 = function(arg0, arg1) {
+ const ret = getObject(arg1).value;
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
+};
+imports.wbg.__wbg_setvalue_688819688274bec0 = function(arg0, arg1, arg2) {
+ var v0 = getCachedStringFromWasm0(arg1, arg2);
+ getObject(arg0).value = v0;
+};
+imports.wbg.__wbg_instanceof_Node_807587297afc161b = function(arg0) {
+ let result;
+ try {
+ result = getObject(arg0) instanceof Node;
+ } catch (_) {
+ result = false;
+ }
+ const ret = result;
+ return ret;
+};
+imports.wbg.__wbg_parentNode_3e06cf96d7693d57 = function(arg0) {
+ const ret = getObject(arg0).parentNode;
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
+};
+imports.wbg.__wbg_childNodes_031aa96d5e3d21b0 = function(arg0) {
+ const ret = getObject(arg0).childNodes;
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_previousSibling_076df2178284ef97 = function(arg0) {
+ const ret = getObject(arg0).previousSibling;
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
+};
+imports.wbg.__wbg_nextSibling_f6396d6fd0b97830 = function(arg0) {
+ const ret = getObject(arg0).nextSibling;
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
+};
+imports.wbg.__wbg_settextContent_cd38ea7d4e0f7260 = function(arg0, arg1, arg2) {
+ var v0 = getCachedStringFromWasm0(arg1, arg2);
+ getObject(arg0).textContent = v0;
+};
+imports.wbg.__wbg_appendChild_ac45d1abddf1b89b = function() { return handleError(function (arg0, arg1) {
+ const ret = getObject(arg0).appendChild(getObject(arg1));
+ return addHeapObject(ret);
+}, arguments) };
+imports.wbg.__wbg_cloneNode_629a1b180e91c467 = function() { return handleError(function (arg0) {
+ const ret = getObject(arg0).cloneNode();
+ return addHeapObject(ret);
+}, arguments) };
+imports.wbg.__wbg_removeChild_139b30d19f579e41 = function() { return handleError(function (arg0, arg1) {
+ const ret = getObject(arg0).removeChild(getObject(arg1));
+ return addHeapObject(ret);
+}, arguments) };
+imports.wbg.__wbg_length_4919f4a62b9b1e94 = function(arg0) {
+ const ret = getObject(arg0).length;
+ return ret;
+};
+imports.wbg.__wbg_writeText_20fb3f7393d34052 = function(arg0, arg1, arg2) {
+ var v0 = getCachedStringFromWasm0(arg1, arg2);
+ const ret = getObject(arg0).writeText(v0);
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_instanceof_FileReader_985ae057ebe3ba9e = function(arg0) {
+ let result;
+ try {
+ result = getObject(arg0) instanceof FileReader;
+ } catch (_) {
+ result = false;
+ }
+ const ret = result;
+ return ret;
+};
+imports.wbg.__wbg_result_3869032b57f861ac = function() { return handleError(function (arg0) {
+ const ret = getObject(arg0).result;
+ return addHeapObject(ret);
+}, arguments) };
+imports.wbg.__wbg_new_8515b7401632bd44 = function() { return handleError(function () {
+ const ret = new FileReader();
+ return addHeapObject(ret);
+}, arguments) };
+imports.wbg.__wbg_readAsArrayBuffer_6475a86a924a8856 = function() { return handleError(function (arg0, arg1) {
+ getObject(arg0).readAsArrayBuffer(getObject(arg1));
+}, arguments) };
+imports.wbg.__wbg_width_85b26c6209197aa9 = function(arg0) {
+ const ret = getObject(arg0).width;
+ return ret;
+};
+imports.wbg.__wbg_instanceof_HtmlSelectElement_c54017bd3db58d85 = function(arg0) {
+ let result;
+ try {
+ result = getObject(arg0) instanceof HTMLSelectElement;
+ } catch (_) {
+ result = false;
+ }
+ const ret = result;
+ return ret;
+};
+imports.wbg.__wbg_value_9991233a797a5fbc = function(arg0, arg1) {
+ const ret = getObject(arg1).value;
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
+};
+imports.wbg.__wbg_setvalue_d953be6ed053da1b = function(arg0, arg1, arg2) {
+ var v0 = getCachedStringFromWasm0(arg1, arg2);
+ getObject(arg0).value = v0;
+};
+imports.wbg.__wbg_sethref_9d76f6c9356e9638 = function() { return handleError(function (arg0, arg1, arg2) {
+ var v0 = getCachedStringFromWasm0(arg1, arg2);
+ getObject(arg0).href = v0;
+}, arguments) };
+imports.wbg.__wbg_origin_648082c4831a5be8 = function() { return handleError(function (arg0, arg1) {
+ const ret = getObject(arg1).origin;
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
+}, arguments) };
+imports.wbg.__wbg_host_a46347409a9511bd = function() { return handleError(function (arg0, arg1) {
+ const ret = getObject(arg1).host;
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
+}, arguments) };
+imports.wbg.__wbg_pathname_6e6871539b48a0e5 = function() { return handleError(function (arg0, arg1) {
+ const ret = getObject(arg1).pathname;
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
+}, arguments) };
+imports.wbg.__wbg_search_20c15d493b8602c5 = function() { return handleError(function (arg0, arg1) {
+ const ret = getObject(arg1).search;
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
+}, arguments) };
+imports.wbg.__wbg_hash_313d7fdf42f6e7d3 = function() { return handleError(function (arg0, arg1) {
+ const ret = getObject(arg1).hash;
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
+}, arguments) };
+imports.wbg.__wbg_instanceof_HtmlStyleElement_76c02d8d225f4fdb = function(arg0) {
+ let result;
+ try {
+ result = getObject(arg0) instanceof HTMLStyleElement;
+ } catch (_) {
+ result = false;
+ }
+ const ret = result;
+ return ret;
+};
+imports.wbg.__wbg_view_2a901bda0727aeb3 = function(arg0) {
+ const ret = getObject(arg0).view;
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
+};
+imports.wbg.__wbg_respond_a799bab31a44f2d7 = function() { return handleError(function (arg0, arg1) {
+ getObject(arg0).respond(arg1 >>> 0);
+}, arguments) };
+imports.wbg.__wbg_instanceof_ClipboardEvent_a455b365be4677bb = function(arg0) {
+ let result;
+ try {
+ result = getObject(arg0) instanceof ClipboardEvent;
+ } catch (_) {
+ result = false;
+ }
+ const ret = result;
+ return ret;
+};
+imports.wbg.__wbg_clipboardData_93c130a72996456a = function(arg0) {
+ const ret = getObject(arg0).clipboardData;
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
+};
+imports.wbg.__wbg_instanceof_DragEvent_29469534b31c3761 = function(arg0) {
+ let result;
+ try {
+ result = getObject(arg0) instanceof DragEvent;
+ } catch (_) {
+ result = false;
+ }
+ const ret = result;
+ return ret;
+};
+imports.wbg.__wbg_dataTransfer_2fb708051ee2c64c = function(arg0) {
+ const ret = getObject(arg0).dataTransfer;
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
+};
+imports.wbg.__wbg_instanceof_InputEvent_4c8c546dc2c8a0db = function(arg0) {
+ let result;
+ try {
+ result = getObject(arg0) instanceof InputEvent;
+ } catch (_) {
+ result = false;
+ }
+ const ret = result;
+ return ret;
+};
+imports.wbg.__wbg_instanceof_ProgressEvent_0193094c90599e88 = function(arg0) {
+ let result;
+ try {
+ result = getObject(arg0) instanceof ProgressEvent;
+ } catch (_) {
+ result = false;
+ }
+ const ret = result;
+ return ret;
+};
+imports.wbg.__wbg_getItem_cab39762abab3e70 = function() { return handleError(function (arg0, arg1, arg2, arg3) {
+ var v0 = getCachedStringFromWasm0(arg2, arg3);
+ const ret = getObject(arg1).getItem(v0);
+ var ptr2 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ var len2 = WASM_VECTOR_LEN;
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len2, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr2, true);
+}, arguments) };
+imports.wbg.__wbg_setItem_9482185c870abba6 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
+ var v0 = getCachedStringFromWasm0(arg1, arg2);
+ var v1 = getCachedStringFromWasm0(arg3, arg4);
+ getObject(arg0).setItem(v0, v1);
+}, arguments) };
+imports.wbg.__wbg_instanceof_HtmlDivElement_a18fc94130bc218e = function(arg0) {
+ let result;
+ try {
+ result = getObject(arg0) instanceof HTMLDivElement;
+ } catch (_) {
+ result = false;
+ }
+ const ret = result;
+ return ret;
+};
+imports.wbg.__wbg_error_09480e4aadca50ad = function(arg0) {
+ console.error(getObject(arg0));
+};
+imports.wbg.__wbg_log_b103404cc5920657 = function(arg0) {
+ console.log(getObject(arg0));
+};
+imports.wbg.__wbg_warn_2b3adb99ce26c314 = function(arg0) {
+ console.warn(getObject(arg0));
+};
+imports.wbg.__wbg_setinnerText_69255282a5d7ed93 = function(arg0, arg1, arg2) {
+ var v0 = getCachedStringFromWasm0(arg1, arg2);
+ getObject(arg0).innerText = v0;
+};
+imports.wbg.__wbg_style_e06c9e03355741e9 = function(arg0) {
+ const ret = getObject(arg0).style;
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_click_025eb185eb16f006 = function(arg0) {
+ getObject(arg0).click();
+};
+imports.wbg.__wbg_focus_06621101cc79f5d8 = function() { return handleError(function (arg0) {
+ getObject(arg0).focus();
+}, arguments) };
+imports.wbg.__wbg_close_cef2400b120c9c73 = function() { return handleError(function (arg0) {
+ getObject(arg0).close();
+}, arguments) };
+imports.wbg.__wbg_enqueue_6f3d433b5e457aea = function() { return handleError(function (arg0, arg1) {
+ getObject(arg0).enqueue(getObject(arg1));
+}, arguments) };
+imports.wbg.__wbg_top_322638693276a225 = function(arg0) {
+ const ret = getObject(arg0).top;
+ return ret;
+};
+imports.wbg.__wbg_right_8b5d6a4fd660b15f = function(arg0) {
+ const ret = getObject(arg0).right;
+ return ret;
+};
+imports.wbg.__wbg_bottom_9c5a8538fdbb5e16 = function(arg0) {
+ const ret = getObject(arg0).bottom;
+ return ret;
+};
+imports.wbg.__wbg_left_ec3af38bed003a86 = function(arg0) {
+ const ret = getObject(arg0).left;
+ return ret;
+};
+imports.wbg.__wbg_target_b7cb1739bee70928 = function(arg0) {
+ const ret = getObject(arg0).target;
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
+};
+imports.wbg.__wbg_defaultPrevented_9e2309e82258aee7 = function(arg0) {
+ const ret = getObject(arg0).defaultPrevented;
+ return ret;
+};
+imports.wbg.__wbg_cancelBubble_0374b329f66f59b5 = function(arg0) {
+ const ret = getObject(arg0).cancelBubble;
+ return ret;
+};
+imports.wbg.__wbg_newwitheventinitdict_8ade740b9035eb27 = function() { return handleError(function (arg0, arg1, arg2) {
+ var v0 = getCachedStringFromWasm0(arg0, arg1);
+ const ret = new Event(v0, getObject(arg2));
+ return addHeapObject(ret);
+}, arguments) };
+imports.wbg.__wbg_composedPath_d1052062308beae5 = function(arg0) {
+ const ret = getObject(arg0).composedPath();
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_preventDefault_c55d86c27b2dfa6e = function(arg0) {
+ getObject(arg0).preventDefault();
+};
+imports.wbg.__wbg_stopPropagation_dd0d50059627b362 = function(arg0) {
+ getObject(arg0).stopPropagation();
+};
+imports.wbg.__wbg_addEventListener_e167f012cbedfa4e = function() { return handleError(function (arg0, arg1, arg2, arg3) {
+ var v0 = getCachedStringFromWasm0(arg1, arg2);
+ getObject(arg0).addEventListener(v0, getObject(arg3));
+}, arguments) };
+imports.wbg.__wbg_addEventListener_14b036ff7cb8747c = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
+ var v0 = getCachedStringFromWasm0(arg1, arg2);
+ getObject(arg0).addEventListener(v0, getObject(arg3), getObject(arg4));
+}, arguments) };
+imports.wbg.__wbg_dispatchEvent_190760297f28fb3d = function() { return handleError(function (arg0, arg1) {
+ const ret = getObject(arg0).dispatchEvent(getObject(arg1));
+ return ret;
+}, arguments) };
+imports.wbg.__wbg_removeEventListener_b6cef5ad085bea8f = function() { return handleError(function (arg0, arg1, arg2, arg3) {
+ var v0 = getCachedStringFromWasm0(arg1, arg2);
+ getObject(arg0).removeEventListener(v0, getObject(arg3));
+}, arguments) };
+imports.wbg.__wbg_instanceof_KeyboardEvent_cb701ff8e9ff53cb = function(arg0) {
+ let result;
+ try {
+ result = getObject(arg0) instanceof KeyboardEvent;
+ } catch (_) {
+ result = false;
+ }
+ const ret = result;
+ return ret;
+};
+imports.wbg.__wbg_altKey_5a6eb49ec8194792 = function(arg0) {
+ const ret = getObject(arg0).altKey;
+ return ret;
+};
+imports.wbg.__wbg_ctrlKey_319ff2374dc7f372 = function(arg0) {
+ const ret = getObject(arg0).ctrlKey;
+ return ret;
+};
+imports.wbg.__wbg_shiftKey_f38dee34420e0d62 = function(arg0) {
+ const ret = getObject(arg0).shiftKey;
+ return ret;
+};
+imports.wbg.__wbg_metaKey_00fdcfadf1968d45 = function(arg0) {
+ const ret = getObject(arg0).metaKey;
+ return ret;
+};
+imports.wbg.__wbg_key_a626396efbca2b95 = function(arg0, arg1) {
+ const ret = getObject(arg1).key;
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
+};
+imports.wbg.__wbg_instanceof_MouseEvent_465e429c6fab5cee = function(arg0) {
+ let result;
+ try {
+ result = getObject(arg0) instanceof MouseEvent;
+ } catch (_) {
+ result = false;
+ }
+ const ret = result;
+ return ret;
+};
+imports.wbg.__wbg_clientX_3967ecd5e962e1b2 = function(arg0) {
+ const ret = getObject(arg0).clientX;
+ return ret;
+};
+imports.wbg.__wbg_clientY_37d418b8d9c0bb52 = function(arg0) {
+ const ret = getObject(arg0).clientY;
+ return ret;
+};
+imports.wbg.__wbg_ctrlKey_957c6c31b62b4550 = function(arg0) {
+ const ret = getObject(arg0).ctrlKey;
+ return ret;
+};
+imports.wbg.__wbg_shiftKey_8c0f9a5ca3ff8f93 = function(arg0) {
+ const ret = getObject(arg0).shiftKey;
+ return ret;
+};
+imports.wbg.__wbg_altKey_d3fbce7596aac8cf = function(arg0) {
+ const ret = getObject(arg0).altKey;
+ return ret;
+};
+imports.wbg.__wbg_metaKey_be0158b14b1cef4a = function(arg0) {
+ const ret = getObject(arg0).metaKey;
+ return ret;
+};
+imports.wbg.__wbg_button_460cdec9f2512a91 = function(arg0) {
+ const ret = getObject(arg0).button;
+ return ret;
+};
+imports.wbg.__wbg_setdata_27c6828c5a5a5ce4 = function(arg0, arg1, arg2) {
+ var v0 = getCachedStringFromWasm0(arg1, arg2);
+ getObject(arg0).data = v0;
+};
+imports.wbg.__wbg_instanceof_HtmlAnchorElement_7a88f0b97085fa30 = function(arg0) {
+ let result;
+ try {
+ result = getObject(arg0) instanceof HTMLAnchorElement;
+ } catch (_) {
+ result = false;
+ }
+ const ret = result;
+ return ret;
+};
+imports.wbg.__wbg_target_fed794e9a6ed73fe = function(arg0, arg1) {
+ const ret = getObject(arg1).target;
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
+};
+imports.wbg.__wbg_href_31456ceb26f92368 = function(arg0, arg1) {
+ const ret = getObject(arg1).href;
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
+};
+imports.wbg.__wbg_append_d510a297e3ba948e = function() { return handleError(function (arg0, arg1) {
+ getObject(arg0).append(getObject(arg1));
+}, arguments) };
+imports.wbg.__wbg_state_b863826253700666 = function() { return handleError(function (arg0) {
+ const ret = getObject(arg0).state;
+ return addHeapObject(ret);
+}, arguments) };
+imports.wbg.__wbg_pushState_fc8b2d0c45854901 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5) {
+ var v0 = getCachedStringFromWasm0(arg2, arg3);
+ var v1 = getCachedStringFromWasm0(arg4, arg5);
+ getObject(arg0).pushState(getObject(arg1), v0, v1);
+}, arguments) };
+imports.wbg.__wbg_replaceState_c3213575ed65bac2 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5) {
+ var v0 = getCachedStringFromWasm0(arg2, arg3);
+ var v1 = getCachedStringFromWasm0(arg4, arg5);
+ getObject(arg0).replaceState(getObject(arg1), v0, v1);
+}, arguments) };
+imports.wbg.__wbg_newwithsrc_4f8c76cff241f93a = function() { return handleError(function (arg0, arg1) {
+ var v0 = getCachedStringFromWasm0(arg0, arg1);
+ const ret = new Audio(v0);
+ return addHeapObject(ret);
+}, arguments) };
+imports.wbg.__wbg_length_6e2f57e8f5058ac4 = function(arg0) {
+ const ret = getObject(arg0).length;
+ return ret;
+};
+imports.wbg.__wbg_item_284906f439cece90 = function(arg0, arg1) {
+ const ret = getObject(arg0).item(arg1 >>> 0);
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
+};
+imports.wbg.__wbg_instanceof_ShadowRoot_72d8e783f8e0093c = function(arg0) {
+ let result;
+ try {
+ result = getObject(arg0) instanceof ShadowRoot;
+ } catch (_) {
+ result = false;
+ }
+ const ret = result;
+ return ret;
+};
+imports.wbg.__wbg_host_fdfe1258b06fe937 = function(arg0) {
+ const ret = getObject(arg0).host;
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_queueMicrotask_12a30234db4045d3 = function(arg0) {
+ queueMicrotask(getObject(arg0));
+};
+imports.wbg.__wbg_queueMicrotask_48421b3cc9052b68 = function(arg0) {
+ const ret = getObject(arg0).queueMicrotask;
+ return addHeapObject(ret);
+};
+imports.wbg.__wbindgen_is_function = function(arg0) {
+ const ret = typeof(getObject(arg0)) === 'function';
+ return ret;
+};
+imports.wbg.__wbg_length_ae22078168b726f5 = function(arg0) {
+ const ret = getObject(arg0).length;
+ return ret;
+};
+imports.wbg.__wbg_next_de3e9db4440638b2 = function(arg0) {
+ const ret = getObject(arg0).next;
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_value_6d39332ab4788d86 = function(arg0) {
+ const ret = getObject(arg0).value;
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_iterator_888179a48810a9fe = function() {
+ const ret = Symbol.iterator;
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_new_525245e2b9901204 = function() {
+ const ret = new Object();
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_self_3093d5d1f7bcb682 = function() { return handleError(function () {
+ const ret = self.self;
+ return addHeapObject(ret);
+}, arguments) };
+imports.wbg.__wbg_window_3bcfc4d31bc012f8 = function() { return handleError(function () {
+ const ret = window.window;
+ return addHeapObject(ret);
+}, arguments) };
+imports.wbg.__wbg_globalThis_86b222e13bdf32ed = function() { return handleError(function () {
+ const ret = globalThis.globalThis;
+ return addHeapObject(ret);
+}, arguments) };
+imports.wbg.__wbg_global_e5a3fe56f8be9485 = function() { return handleError(function () {
+ const ret = global.global;
+ return addHeapObject(ret);
+}, arguments) };
+imports.wbg.__wbg_decodeURI_27d956972029c70b = function() { return handleError(function (arg0, arg1) {
+ var v0 = getCachedStringFromWasm0(arg0, arg1);
+ const ret = decodeURI(v0);
+ return addHeapObject(ret);
+}, arguments) };
+imports.wbg.__wbg_get_3baa728f9d58d3f6 = function(arg0, arg1) {
+ const ret = getObject(arg0)[arg1 >>> 0];
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_isArray_8364a5371e9737d8 = function(arg0) {
+ const ret = Array.isArray(getObject(arg0));
+ return ret;
+};
+imports.wbg.__wbg_instanceof_ArrayBuffer_61dfc3198373c902 = function(arg0) {
+ let result;
+ try {
+ result = getObject(arg0) instanceof ArrayBuffer;
+ } catch (_) {
+ result = false;
+ }
+ const ret = result;
+ return ret;
+};
+imports.wbg.__wbg_new_796382978dfd4fb0 = function(arg0, arg1) {
+ var v0 = getCachedStringFromWasm0(arg0, arg1);
+ const ret = new Error(v0);
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_newnoargs_76313bd6ff35d0f2 = function(arg0, arg1) {
+ var v0 = getCachedStringFromWasm0(arg0, arg1);
+ const ret = new Function(v0);
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_call_1084a111329e68ce = function() { return handleError(function (arg0, arg1) {
+ const ret = getObject(arg0).call(getObject(arg1));
+ return addHeapObject(ret);
+}, arguments) };
+imports.wbg.__wbg_call_89af060b4e1523f2 = function() { return handleError(function (arg0, arg1, arg2) {
+ const ret = getObject(arg0).call(getObject(arg1), getObject(arg2));
+ return addHeapObject(ret);
+}, arguments) };
+imports.wbg.__wbg_next_f9cb570345655b9a = function() { return handleError(function (arg0) {
+ const ret = getObject(arg0).next();
+ return addHeapObject(ret);
+}, arguments) };
+imports.wbg.__wbg_done_bfda7aa8f252b39f = function(arg0) {
+ const ret = getObject(arg0).done;
+ return ret;
+};
+imports.wbg.__wbg_getDate_52f8a749afd35eda = function(arg0) {
+ const ret = getObject(arg0).getDate();
+ return ret;
+};
+imports.wbg.__wbg_getFullYear_9649dddf8a157b21 = function(arg0) {
+ const ret = getObject(arg0).getFullYear();
+ return ret;
+};
+imports.wbg.__wbg_getMonth_e3a0afc07cbc1328 = function(arg0) {
+ const ret = getObject(arg0).getMonth();
+ return ret;
+};
+imports.wbg.__wbg_getTimezoneOffset_c9929a3cc94500fe = function(arg0) {
+ const ret = getObject(arg0).getTimezoneOffset();
+ return ret;
+};
+imports.wbg.__wbg_new0_65387337a95cf44d = function() {
+ const ret = new Date();
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_now_b7a162010a9e75b4 = function() {
+ const ret = Date.now();
+ return ret;
+};
+imports.wbg.__wbg_is_009b1ef508712fda = function(arg0, arg1) {
+ const ret = Object.is(getObject(arg0), getObject(arg1));
+ return ret;
+};
+imports.wbg.__wbg_exec_a29a4ce5544bd3be = function(arg0, arg1, arg2) {
+ var v0 = getCachedStringFromWasm0(arg1, arg2);
+ const ret = getObject(arg0).exec(v0);
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
+};
+imports.wbg.__wbg_new_13847c66f41dda63 = function(arg0, arg1, arg2, arg3) {
+ var v0 = getCachedStringFromWasm0(arg0, arg1);
+ var v1 = getCachedStringFromWasm0(arg2, arg3);
+ const ret = new RegExp(v0, v1);
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_new_b85e72ed1bfd57f9 = function(arg0, arg1) {
+ try {
+ var state0 = {a: arg0, b: arg1};
+ var cb0 = (arg0, arg1) => {
+ const a = state0.a;
+ state0.a = 0;
+ try {
+ return __wbg_adapter_470(a, state0.b, arg0, arg1);
+ } finally {
+ state0.a = a;
+ }
+ };
+ const ret = new Promise(cb0);
+ return addHeapObject(ret);
+ } finally {
+ state0.a = state0.b = 0;
+ }
+};
+imports.wbg.__wbg_resolve_570458cb99d56a43 = function(arg0) {
+ const ret = Promise.resolve(getObject(arg0));
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_then_95e6edc0f89b73b1 = function(arg0, arg1) {
+ const ret = getObject(arg0).then(getObject(arg1));
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_then_876bb3c633745cc6 = function(arg0, arg1, arg2) {
+ const ret = getObject(arg0).then(getObject(arg1), getObject(arg2));
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_buffer_b7b08af79b0b0974 = function(arg0) {
+ const ret = getObject(arg0).buffer;
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_newwithbyteoffsetandlength_8a2cb9ca96b27ec9 = function(arg0, arg1, arg2) {
+ const ret = new Uint8Array(getObject(arg0), arg1 >>> 0, arg2 >>> 0);
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_new_ea1883e1e5e86686 = function(arg0) {
+ const ret = new Uint8Array(getObject(arg0));
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_newwithlength_ec548f448387c968 = function(arg0) {
+ const ret = new Uint8Array(arg0 >>> 0);
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_buffer_0710d1b9dbe2eea6 = function(arg0) {
+ const ret = getObject(arg0).buffer;
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_subarray_7c2e3576afe181d1 = function(arg0, arg1, arg2) {
+ const ret = getObject(arg0).subarray(arg1 >>> 0, arg2 >>> 0);
+ return addHeapObject(ret);
+};
+imports.wbg.__wbg_length_8339fcf5d8ecd12e = function(arg0) {
+ const ret = getObject(arg0).length;
+ return ret;
+};
+imports.wbg.__wbg_byteLength_850664ef28f3e42f = function(arg0) {
+ const ret = getObject(arg0).byteLength;
+ return ret;
+};
+imports.wbg.__wbg_byteOffset_ea14c35fa6de38cc = function(arg0) {
+ const ret = getObject(arg0).byteOffset;
+ return ret;
+};
+imports.wbg.__wbg_set_d1e79e2388520f18 = function(arg0, arg1, arg2) {
+ getObject(arg0).set(getObject(arg1), arg2 >>> 0);
+};
+imports.wbg.__wbg_get_224d16597dbbfd96 = function() { return handleError(function (arg0, arg1) {
+ const ret = Reflect.get(getObject(arg0), getObject(arg1));
+ return addHeapObject(ret);
+}, arguments) };
+imports.wbg.__wbg_set_eacc7d73fefaafdf = function() { return handleError(function (arg0, arg1, arg2) {
+ const ret = Reflect.set(getObject(arg0), getObject(arg1), getObject(arg2));
+ return ret;
+}, arguments) };
+imports.wbg.__wbindgen_debug_string = function(arg0, arg1) {
+ const ret = debugString(getObject(arg1));
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
+};
+imports.wbg.__wbindgen_throw = function(arg0, arg1) {
+ throw new Error(getStringFromWasm0(arg0, arg1));
+};
+imports.wbg.__wbindgen_rethrow = function(arg0) {
+ throw takeObject(arg0);
+};
+imports.wbg.__wbindgen_memory = function() {
+ const ret = wasm.memory;
+ return addHeapObject(ret);
+};
+imports.wbg.__wbindgen_closure_wrapper2721 = function(arg0, arg1, arg2) {
+ const ret = makeMutClosure(arg0, arg1, 794, __wbg_adapter_38);
+ return addHeapObject(ret);
+};
+imports.wbg.__wbindgen_closure_wrapper33341 = function(arg0, arg1, arg2) {
+ const ret = makeMutClosure(arg0, arg1, 4765, __wbg_adapter_41);
+ return addHeapObject(ret);
+};
+imports.wbg.__wbindgen_closure_wrapper33752 = function(arg0, arg1, arg2) {
+ const ret = makeMutClosure(arg0, arg1, 4790, __wbg_adapter_44);
+ return addHeapObject(ret);
+};
+imports.wbg.__wbindgen_closure_wrapper35883 = function(arg0, arg1, arg2) {
+ const ret = makeMutClosure(arg0, arg1, 4815, __wbg_adapter_47);
+ return addHeapObject(ret);
+};
+
+return imports;
+}
+
+function __wbg_init_memory(imports, memory) {
+
+}
+
+function __wbg_finalize_init(instance, module) {
+ wasm = instance.exports;
+ __wbg_init.__wbindgen_wasm_module = module;
+ cachedDataViewMemory0 = null;
+ cachedUint8ArrayMemory0 = null;
+
+
+ wasm.__wbindgen_start();
+ return wasm;
+}
+
+function initSync(module) {
+ if (wasm !== undefined) return wasm;
+
+
+ if (typeof module !== 'undefined' && Object.getPrototypeOf(module) === Object.prototype)
+ ({module} = module)
+ else
+ console.warn('using deprecated parameters for `initSync()`; pass a single object instead')
+
+ const imports = __wbg_get_imports();
+
+ __wbg_init_memory(imports);
+
+ if (!(module instanceof WebAssembly.Module)) {
+ module = new WebAssembly.Module(module);
+ }
+
+ const instance = new WebAssembly.Instance(module, imports);
+
+ return __wbg_finalize_init(instance, module);
+}
+
+async function __wbg_init(module_or_path) {
+ if (wasm !== undefined) return wasm;
+
+
+ if (typeof module_or_path !== 'undefined' && Object.getPrototypeOf(module_or_path) === Object.prototype)
+ ({module_or_path} = module_or_path)
+ else
+ console.warn('using deprecated parameters for the initialization function; pass a single object instead')
+
+ if (typeof module_or_path === 'undefined') {
+ module_or_path = new URL('site_bg.wasm', import.meta.url);
+ }
+ const imports = __wbg_get_imports();
+
+ if (typeof module_or_path === 'string' || (typeof Request === 'function' && module_or_path instanceof Request) || (typeof URL === 'function' && module_or_path instanceof URL)) {
+ module_or_path = fetch(module_or_path);
+ }
+
+ __wbg_init_memory(imports);
+
+ const { instance, module } = await __wbg_load(await module_or_path, imports);
+
+ return __wbg_finalize_init(instance, module);
+}
+
+export { initSync };
+export default __wbg_init;
diff --git a/docs/site-2c10351283036f17_bg.wasm b/docs/site-2c10351283036f17_bg.wasm
new file mode 100644
index 000000000..a4e3bbf72
Binary files /dev/null and b/docs/site-2c10351283036f17_bg.wasm differ
diff --git a/docs/styles-99c6525f8658bb5f.css b/docs/styles-99c6525f8658bb5f.css
new file mode 100644
index 000000000..f31060294
--- /dev/null
+++ b/docs/styles-99c6525f8658bb5f.css
@@ -0,0 +1,1509 @@
+@font-face {
+ font-family: "Code Font";
+ src: url(Uiua386.ttf) format("truetype");
+}
+
+html * {
+ font-family: "Segoe UI", "Arial", sans-serif;
+}
+
+html {
+ font-size: 115%;
+ font-weight: 500;
+}
+
+body {
+ margin: 0;
+}
+
+p {
+ line-height: 1.5em;
+}
+
+h2 {
+ margin: 1.8em 0 0.5em 0;
+ padding-bottom: 0.3em;
+ border-bottom-width: 0.08em;
+ border-bottom-style: solid;
+ border-color: #888a;
+}
+
+.header {
+ position: relative;
+}
+
+a.header,
+a:visited.header,
+a:link.header {
+ text-decoration: none;
+ color: inherit;
+}
+
+a.header::before {
+ position: absolute;
+ left: -1.5em;
+ bottom: 0.4em;
+ content: "🔗";
+ opacity: 0;
+ font-size: 0.6em;
+ transition: opacity 0.2s;
+}
+
+a.header:hover::before {
+ opacity: 0.5;
+}
+
+h1>a>code,
+h2>a>code {
+ font-weight: normal;
+}
+
+button {
+ border-width: 0;
+ border-radius: 0.5em;
+ padding: 0.2em;
+ display: inline-block;
+ position: relative;
+}
+
+button:active {
+ transform: translateY(0.1em);
+}
+
+code {
+ font-family: "Code Font", monospace;
+ border-radius: 0.2em;
+ padding: 0.2em;
+ position: relative;
+ white-space: nowrap;
+}
+
+th,
+td {
+ padding: 0.3em;
+ border-radius: 0.5em;
+}
+
+th {
+ text-align: left;
+}
+
+tr:nth-child(even) {
+ background-color: #0001;
+}
+
+.bordered-table {
+ border: 0.2em solid #0005;
+ border-radius: 0.5em;
+}
+
+.header-centered-table>tr>th {
+ text-align: center;
+
+}
+
+.cell-centered-table>tr>td {
+ text-align: center;
+}
+
+li {
+ margin: 0.3em 0;
+}
+
+@media (prefers-color-scheme: dark) {
+
+ body,
+ #header-uiua,
+ .spoiler:hover {
+ color: #d1daec;
+ }
+
+ body,
+ .spoiler:hover {
+ background-color: #171d22;
+ }
+
+ #editor {
+ outline: 0.1em solid #606468;
+ background-color: #19232d;
+ }
+
+ .code,
+ .input-div,
+ input[type=text],
+ select,
+ option,
+ #settings>*>*>input,
+ #settings>*>*>select {
+ color: #d1daec;
+ background-color: #1d2c3a;
+ }
+
+ button {
+ color: #d1daec;
+ background-color: #1d2c3a;
+ }
+
+ button:hover {
+ background-color: #2d3c4a;
+ }
+
+ a:link {
+ color: #6fadea;
+ }
+
+ a:visited {
+ color: #947bec;
+ }
+
+ code {
+ background-color: #0004;
+ }
+
+ .important-button {
+ background-color: #33577b;
+ }
+
+ .important-button:hover {
+ background-color: #579;
+ }
+
+ .tutorial-nav>* {
+ background-color: #1d2c3a;
+ }
+
+ tr:nth-child(even) {
+ background-color: #0001;
+ }
+
+ .glyph-button:hover,
+ .combinator-diagram {
+ background-color: #0003;
+ }
+
+ .code-entry {
+ caret-color: white;
+ }
+
+ #subtitle {
+ color: #d1daecc0;
+ }
+}
+
+@media (prefers-color-scheme: light) {
+
+ body,
+ #header-uiua,
+ .spoiler:hover {
+ color: #344;
+ }
+
+ body,
+ .spoiler:hover {
+ background-color: #c6e7ec;
+ }
+
+ #editor {
+ background-color: #dff2f3;
+ outline: 0.1em solid #0004;
+ }
+
+ .code,
+ .input-div,
+ input[type=text],
+ select,
+ option,
+ #settings>*>*>input,
+ #settings>*>*>select {
+ color: #344;
+ background-color: #f4f6f6;
+ }
+
+ button {
+ color: #344;
+ background-color: #f6f8f8;
+ }
+
+ button:hover {
+ background-color: #fdffff;
+ }
+
+ a:link {
+ color: #0099ad;
+ }
+
+ a:visited {
+ color: #6a4bfb;
+ }
+
+ code {
+ background-color: #fff8;
+ }
+
+ .important-button {
+ background-color: #aadae0;
+ }
+
+ .important-button:hover {
+ background-color: #bee2e7;
+ }
+
+ .tutorial-nav>* {
+ background-color: #f6f8f8;
+ }
+
+ tr:nth-child(even) {
+ background-color: #fff1;
+ }
+
+ .glyph-button:hover,
+ .combinator-diagram {
+ background-color: #fffa;
+ }
+
+ .code-entry {
+ caret-color: black;
+ }
+
+ #subtitle {
+ color: #344c;
+ }
+}
+
+#top {
+ margin: 2em auto;
+ width: max(10em, min(90%, 53em));
+}
+
+#header {
+ display: flex;
+ justify-content: space-between;
+ align-items: last baseline;
+ flex-wrap: wrap;
+ gap: 1em;
+ margin-bottom: 1em;
+}
+
+
+#header-left {
+ display: flex;
+ align-items: last baseline;
+ margin: -1em 0;
+}
+
+#header-uiua {
+ text-decoration: none;
+ white-space: nowrap;
+}
+
+#subtitle {
+ margin-left: 1.5em;
+ font-size: 1em;
+ font-weight: bold;
+ font-style: italic;
+}
+
+.spoiler {
+ color: #0000;
+ background-color: #0008;
+ border-radius: 0.5em;
+}
+
+.long-subtitle {
+ font-size: 0.9em;
+}
+
+.long-subtitle>div {
+ display: flex;
+ gap: 0.5em;
+ flex-wrap: nowrap;
+ white-space: nowrap;
+}
+
+#nav {
+ display: flex;
+ gap: 1em;
+ flex-wrap: nowrap;
+ align-items: baseline;
+}
+
+#links {
+ font-size: 1.2em;
+ display: flex;
+ justify-content: center;
+ flex-wrap: wrap;
+ gap: 1em;
+ margin-bottom: 1em;
+ align-content: flex-start;
+}
+
+#links>* {
+ display: flex;
+ gap: 1em;
+ flex-wrap: wrap;
+ justify-content: space-between;
+ align-content: flex-start;
+}
+
+.main-text {
+ font-size: 120%;
+ text-align: center;
+}
+
+.wee-wuh-span {
+ font-size: 70%;
+ opacity: 0.8;
+}
+
+.features {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
+ gap: min(3em, 3vw);
+ width: min(120%, 90vw);
+ margin-left: calc(-0.5 * (min(120%, 90vw) - 100%));
+}
+
+.features>* {
+ flex: 1 1 22em;
+ width: 0;
+}
+
+#editor {
+ border-radius: 0.5em;
+ position: relative;
+}
+
+#drag-message {
+ position: absolute;
+ inset: 0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ background-color: #0008;
+ font-size: 2em;
+}
+
+#editor-wrapper {
+ margin-bottom: 0.5em;
+ font-size: min(1em, 3.5vw);
+}
+
+.small-editor {
+ font-size: 1.2em;
+}
+
+.medium-editor {
+ font-size: 1.4em;
+}
+
+#settings {
+ display: flex;
+ justify-content: space-between;
+ font-size: 0.82em;
+ padding: 0.2em;
+ gap: 0.5em;
+}
+
+#settings>* {
+ display: flex;
+ align-items: center;
+ flex-wrap: wrap;
+ gap: 0.2em 1em;
+}
+
+#settings-left {
+ width: 85%;
+ justify-content: space-between;
+}
+
+#settings-right {
+ flex-direction: column;
+ align-items: flex-end;
+}
+
+#settings>*>* {
+ display: inline-block;
+ white-space: nowrap;
+}
+
+input[type=number] {
+ appearance: textfield;
+ -moz-appearance: textfield;
+}
+
+.code-block {
+ display: block;
+ white-space: pre-wrap;
+ padding: 0.8em;
+}
+
+select,
+option,
+#settings>*>*>input,
+#settings>*>*>select {
+ border-radius: 0.5em;
+ border: none;
+ margin-left: 0.5em;
+}
+
+#settings>*>*>input[type=number] {
+ width: 3em;
+}
+
+#code-area {
+ position: relative;
+}
+
+.code-outer {
+ text-align: left;
+ border-radius: 0.5em;
+ width: 100%;
+ resize: vertical;
+ box-sizing: border-box;
+ outline: none;
+ border: none;
+ padding: 0.3em;
+ min-height: 1.8em;
+ display: flex;
+ gap: 0.1em;
+ overflow-x: auto;
+ overflow-y: hidden;
+}
+
+.code-and-overlay {
+ width: 100%;
+ position: relative;
+}
+
+.code-entry {
+ margin: 0.1em 0 0 0;
+ padding: 0;
+ position: absolute;
+ outline: none;
+ border: none;
+ box-sizing: border-box;
+ /* background-color: #0002; */
+ /* color: #0008; */
+ background-color: transparent;
+ color: transparent;
+ resize: none;
+ font-family: "Code Font", monospace;
+ font-size: inherit;
+ line-height: 1.25em;
+ overflow-wrap: normal;
+ white-space: pre;
+ overflow: hidden;
+ height: 100%;
+}
+
+.code-entry::selection {
+ color: transparent;
+ background-color: #0078d7;
+}
+
+.code-overlay {
+ margin: 0;
+ padding: 0;
+ position: absolute;
+ width: 100%;
+ pointer-events: none;
+ white-space: pre;
+}
+
+.code-line {
+ height: 1.25em;
+ padding: 0;
+ margin: 0;
+}
+
+.line-numbers {
+ min-width: 1.5em;
+}
+
+@media (prefers-color-scheme: dark) {
+ .line-numbers {
+ color: #3f4b5d;
+ }
+}
+
+@media (prefers-color-scheme: light) {
+ .line-numbers {
+ color: #bcc9ca;
+ }
+}
+
+.code-span {
+ font-size: 1em;
+ font-family: "Code Font", monospace;
+ white-space: pre;
+ text-decoration: none;
+}
+
+.code-hover {
+ display: none;
+ position: fixed;
+ font-family: "Code Font", monospace;
+ font-size: 0.7em;
+ color: #eee;
+ background-color: #000c;
+ padding: 0.2em;
+ border-radius: 0.2em;
+ pointer-events: none;
+ z-index: 1;
+ text-decoration: none;
+ white-space: pre-wrap;
+ overflow: visible;
+ -webkit-text-fill-color: #eee;
+ -moz-text-fill-color: #eee;
+}
+
+.ctrl-pressed .code-underline:hover {
+ text-decoration: underline;
+ cursor: pointer;
+}
+
+.output-frame {
+ display: flex;
+ justify-content: space-between;
+ min-height: 1.9em;
+}
+
+.output-lines {
+ overflow-x: auto;
+}
+
+.output-diagnostics {
+ white-space: pre-wrap;
+ text-align: left;
+ margin-left: 1.75em;
+ padding: 0.3em 0;
+ font-family: "Code Font", monospace;
+}
+
+.output-wrapper {
+ transform: rotateX(180deg);
+ overflow-x: auto;
+}
+
+.output {
+ white-space: pre;
+ text-align: left;
+ margin-left: 1.85em;
+ padding: 0.4em 0;
+ font-family: "Code Font", monospace;
+ transform: rotateX(180deg);
+}
+
+.output:empty,
+.output-diagnostics:empty {
+ display: none;
+}
+
+.output-item,
+.output-report {
+ font-family: inherit;
+}
+
+#code-buttons {
+ margin: 0.2em 0.2em 0.2em 0;
+ display: flex;
+ flex-wrap: nowrap;
+ right: 0;
+ max-height: 1.5em;
+}
+
+.code-button {
+ font-size: 0.9em;
+ margin: 0 0 0 0.2em;
+ height: auto;
+ text-align: center;
+ text-justify: center;
+}
+
+.important-button {
+ animation: fadeAnimation 2s infinite;
+}
+
+.output-line {
+ font-family: "Code Font", monospace;
+ font-size: inherit;
+ white-space: pre;
+}
+
+.output-wrap-line {
+ white-space: pre-wrap;
+}
+
+.output-report {
+ font-size: 0.89em;
+}
+
+.output-error {
+ color: #f44;
+}
+
+.output-warning {
+ color: #fb0;
+}
+
+.output-advice {
+ color: #2af;
+}
+
+.output-style {
+ color: #0a0;
+}
+
+.output-info {
+ color: #1cf;
+}
+
+.output-faint {
+ opacity: 0.75;
+}
+
+.output-fainter {
+ opacity: 0.55;
+}
+
+.output-media-wrapper {
+ display: flex;
+}
+
+.output-image {
+ border-radius: 0.5em;
+ max-width: 50vw;
+}
+
+.output-image-label {
+ font-size: 1em;
+ font-family: "Code Font", monospace;
+ color: white;
+ text-shadow: 0 0 0.5em black;
+ /* put the label in the corner of the image */
+ position: absolute;
+ margin-top: 0.3em;
+ margin-left: 0.4em;
+}
+
+.output-audio {
+ border-radius: 0.5em;
+ max-width: 50vw;
+}
+
+.output-audio-label {
+ font-size: 1em;
+ font-family: "Code Font", monospace;
+ margin-right: 0.5em;
+ align-self: center;
+}
+
+#code-right-side {
+ display: flex;
+ position: absolute;
+ top: 0.1em;
+ right: 0.2em;
+ padding-right: 0.3em;
+ font-size: min(1em, 3vw);
+ align-items: center;
+}
+
+#glyphs-toggle-button {
+ font-weight: bolder;
+ font-size: 0.9em;
+}
+
+#glyphs-toggle-button:hover:after {
+ font-size: 0.6em;
+}
+
+.editor-right-button {
+ font-weight: bolder;
+ opacity: 0.5;
+}
+
+.editor-right-button:hover {
+ opacity: 1;
+}
+
+.info-button:hover::after,
+.editor-right-button:hover::after,
+.experimental-icon:hover::after {
+ content: attr(data-title);
+ position: absolute;
+ font-family: "Code Font", monospace;
+ font-size: 1em;
+ left: calc(-8em - 50%);
+ bottom: 1.5em;
+ color: #eee;
+ padding: 0.2em;
+ border-radius: 0.2em;
+ pointer-events: none;
+}
+
+.editor-right-button:hover::after,
+.experimental-icon:hover::after {
+ background-color: #000b;
+ width: 8em;
+}
+
+.info-button:hover::after {
+ background-color: #000d;
+ width: 24em;
+ white-space: pre-wrap;
+ text-align: left;
+}
+
+.experimental-icon {
+ position: relative;
+}
+
+.experimental-icon:hover::after {
+ left: 100% !important;
+ bottom: 0 !important;
+}
+
+#example-tracker {
+ margin-left: 0.5em;
+ font-size: 0.8em;
+}
+
+.glyph-buttons {
+ padding: 0.1em;
+ font-size: 1.4em;
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-evenly;
+ align-items: baseline;
+}
+
+.glyph-button {
+ font-family: "Code Font", monospace;
+ font-size: 0.84em;
+ padding: 0.045em;
+ margin: 0em;
+ background-color: transparent;
+}
+
+.glyph-button:hover::after {
+ content: attr(data-title);
+ position: absolute;
+ font-family: "Code Font", monospace;
+ font-size: 0.7em;
+ bottom: 100%;
+ color: #eee;
+ background-color: #000a;
+ padding: 0.1em;
+ border-radius: 0.2em;
+ left: -1em;
+ width: 7em;
+ pointer-events: none;
+ z-index: 1;
+ white-space: pre-wrap;
+ -webkit-text-fill-color: #eee;
+ -moz-text-fill-color: #eee;
+}
+
+.experimental-glyph-button {
+ display: none;
+}
+
+.format-button {
+ display: none;
+}
+
+.run-format-button:hover::after {
+ content: attr(data-title);
+ position: absolute;
+ font-family: "Code Font", monospace;
+ font-size: 0.8em;
+ bottom: 110%;
+ right: 0%;
+ color: #eee;
+ background-color: #000a;
+ padding: 0.1em;
+ border-radius: 0.2em;
+ pointer-events: none;
+ z-index: 2;
+ white-space: pre;
+ -webkit-text-fill-color: #eee;
+ -moz-text-fill-color: #eee;
+}
+
+.prim-code-a {
+ text-decoration: none;
+ white-space: nowrap;
+}
+
+.prim-glyph {
+ font-weight: 400;
+}
+
+.prim-code:hover::after {
+ content: attr(data-title);
+ position: absolute;
+ font-family: "Code Font", monospace;
+ font-size: 0.8em;
+ bottom: 100%;
+ color: #eee;
+ background-color: #000d;
+ padding: 0.2em;
+ border-radius: 0.2em;
+ left: 0;
+ pointer-events: none;
+ width: 10em;
+ text-decoration: none;
+ white-space: pre-wrap;
+ overflow: visible;
+ line-height: 1em;
+ z-index: 1;
+ -webkit-text-fill-color: #eee;
+ -moz-text-fill-color: #eee;
+}
+
+.glyph-doc {
+ position: absolute;
+ top: min(10%, 1em);
+ left: 10%;
+ padding: 0.5em;
+ font-size: 0.75em;
+ border-radius: 0.5em;
+ max-width: 80%;
+ white-space: pre-wrap;
+ font-family: "Code Font", monospace;
+ z-index: 1;
+}
+
+.additional-functions {
+ font-family: "Code Font", monospace;
+ align-self: center;
+ font-size: 0.7em;
+ width: 1.1em;
+ white-space: pre;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ margin-left: 0;
+ margin-right: 0;
+ text-align: center;
+}
+
+.additional-functions::-ms-expand {
+ display: none;
+}
+
+.additional-functions>* {
+ font-family: "Code Font", monospace;
+}
+
+.named-function-button {
+ font-family: "Code Font", monospace;
+ white-space: pre;
+ text-align: left;
+}
+
+@media (prefers-color-scheme: dark) {
+
+ .glyph-doc {
+ background-color: #000c;
+ }
+
+ .glyph-doc-ctrl-click {
+ color: #aaa;
+ }
+}
+
+@media (prefers-color-scheme: light) {
+
+ .glyph-doc {
+ background-color: #fffd;
+ }
+
+ .glyph-doc-ctrl-click {
+ color: #777;
+ }
+}
+
+.glyph-doc-ctrl-click {
+ font-size: 0.7em;
+}
+
+.code-font {
+ font-family: "Code Font", monospace;
+}
+
+.combinator-diagram {
+ border-radius: 0.5em;
+ height: 8em;
+}
+
+@media (prefers-color-scheme: dark) {
+ .stack-function {
+ color: #d1daec;
+ }
+}
+
+@media (prefers-color-scheme: light) {
+ .stack-function {
+ color: #344;
+ }
+}
+
+.private-binding>* {
+ opacity: 0.75;
+}
+
+.module {
+ color: #d7be8c;
+}
+
+.noadic-function {
+ color: #ed5e6a;
+}
+
+.monadic-function {
+ color: #95d16a;
+}
+
+.dyadic-function {
+ color: #54b0fc;
+}
+
+.triadic-function {
+ color: #8078f1;
+}
+
+.tetradic-function {
+ color: #f576d8;
+}
+
+.variadic-function {
+ background-image: linear-gradient(170deg,
+ #ed5e6a 34%,
+ #95d16a 34%,
+ #95d16a 45%,
+ #54b0fc 45%,
+ #54b0fc 56%,
+ #8078f1 56%,
+ #8078f1 67%,
+ #f576d8 67%);
+}
+
+.monadic-modifier {
+ color: #f0c36f;
+}
+
+.dyadic-modifier {
+ color: #cc6be9;
+}
+
+.triadic-modifier {
+ color: #F5A9B8
+}
+
+.space-character {
+ border-width: 2px;
+ border-radius: 0.3em;
+ border-style: dashed;
+ margin: 0 -2px;
+}
+
+@media (prefers-color-scheme: dark) {
+ .string-literal-span {
+ color: #20f9fc;
+ }
+
+ .space-character {
+ border-color: #20f9fc80;
+ }
+
+ .strand-span {
+ color: #fff8;
+ }
+}
+
+@media (prefers-color-scheme: light) {
+ .string-literal-span {
+ color: #1c9;
+ }
+
+ .space-character {
+ border-color: #1c98;
+ }
+
+ .strand-span {
+ color: #0008;
+ }
+}
+
+.number-literal {
+ color: #f85;
+}
+
+
+.comment-span {
+ color: #888;
+}
+
+.value-hint {
+ color: #8888;
+}
+
+@media (prefers-color-scheme: dark) {
+ .output-a {
+ color: #cff;
+ }
+
+ .output-b {
+ color: #ccf;
+ }
+
+ .output-c {
+ color: #fcf;
+ }
+
+ .output-d {
+ color: #fcc;
+ }
+
+ .output-e {
+ color: #ffc;
+ }
+
+ .output-f {
+ color: #cfc;
+ }
+}
+
+@media (prefers-color-scheme: light) {
+
+ .output-a {
+ color: #225;
+ }
+
+ .output-b {
+ color: #525;
+ }
+
+ .output-c {
+ color: #522;
+ }
+
+ .output-d {
+ color: #552;
+ }
+
+ .output-e {
+ color: #252;
+ }
+
+ .output-f {
+ color: #255;
+ }
+}
+
+#editor-help {
+ margin: 0.4em 0 0 0;
+ font-size: 1em;
+ opacity: 0.5;
+ display: flex;
+ justify-content: space-between;
+ gap: 0.5em;
+}
+
+#editor-help:empty {
+ display: none;
+}
+
+#editor-help>* {
+ line-height: 1em;
+ margin: 0;
+ white-space: pre-wrap;
+}
+
+.sound-button {
+ background-color: transparent;
+}
+
+.tutorial-nav {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ font-size: 1.1em;
+ gap: 0.5em;
+}
+
+.tutorial-nav>* {
+ border-radius: 0.5em;
+ border-color: #0003;
+ border-radius: 0.5em;
+ padding: 0.5em;
+}
+
+.tutorial-nav>*:empty {
+ background-color: #0000;
+}
+
+.primitive-list {
+ display: flex;
+ flex-wrap: wrap;
+ flex-direction: column;
+}
+
+.primitive-list>* {
+ margin-bottom: 0.5em;
+}
+
+#ascii-glyphs {
+ display: flex;
+ justify-content: space-evenly;
+ flex-wrap: wrap;
+}
+
+.input-div {
+ display: flex;
+ align-items: center;
+ font-size: 1em;
+ border-radius: 0.5em;
+ padding: 0.5em;
+ width: min(100%, max(30%, 22em));
+}
+
+input[type=text] {
+ font-size: 1em;
+ border-radius: 0.5em;
+ padding: 0 0.5em;
+ outline: none;
+ border: none;
+ width: 100%;
+}
+
+#function-search {
+ scroll-margin-top: 1em;
+ scroll-margin-bottom: 1em;
+}
+
+#function-search-wrapper {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.const-desc {
+ display: inline-block;
+ white-space: pre-wrap;
+}
+
+.running-text {
+ animation: fadeAnimation 1s infinite;
+}
+
+.slow-pulse {
+ animation: pulseAnimation 2s infinite;
+}
+
+@keyframes fadeAnimation {
+
+ 0%,
+ 100% {
+ opacity: 0.5;
+ }
+
+ 50% {
+ opacity: 1;
+ }
+}
+
+
+@keyframes pulseAnimation {
+
+ 0%,
+ 100% {
+ transform: scale(1) translate(0);
+ }
+
+ 50% {
+ transform: scale(1, 1.1) translate(0, -0.05em);
+ }
+}
+
+.uiuism-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.pls-no-block {
+ font-size: 0.7em;
+}
+
+a.clean {
+ text-decoration: none;
+}
+
+.experimental {
+ color: #db2;
+}
+
+.text-gradient {
+ background-size: 100%;
+ background-clip: text;
+ -webkit-background-clip: text;
+ -moz-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ -moz-text-fill-color: transparent;
+}
+
+.trans {
+ background-image: linear-gradient(180deg,
+ #5BCEFA 34%,
+ #F5A9B8 34%,
+ #F5A9B8 45%,
+ #FFFFFF 45%,
+ #FFFFFF 56%,
+ #F5A9B8 56%,
+ #F5A9B8 67%,
+ #5BCEFA 67%);
+}
+
+.bi {
+ background-image: linear-gradient(180deg,
+ #D60270 45%,
+ #9B4F96 45%,
+ #9B4F96 64%,
+ #0038A8 64%);
+}
+
+.pan {
+ background-image: linear-gradient(180deg,
+ #FF218C 45%,
+ #FFD800 45%,
+ #FFD800 64%,
+ #21B1FF 64%);
+}
+
+.gay {
+ background-image: linear-gradient(180deg,
+ #E40303 30%,
+ #FFA52C 30%,
+ #FFA52C 40%,
+ #FFFF41 40%,
+ #FFFF41 50%,
+ #008018 50%,
+ #008018 60%,
+ #0000F9 60%,
+ #0000F9 70%,
+ #86007D 70%);
+}
+
+.ace {
+ background-image: linear-gradient(180deg,
+ #000000 30%,
+ #A3A3A3 30%,
+ #A3A3A3 50%,
+ #FFFFFF 50%,
+ #FFFFFF 70%,
+ #800080 70%);
+}
+
+.aro {
+ background-image: linear-gradient(180deg,
+ #000000 36%,
+ #A9A9A9 36%,
+ #A9A9A9 47%,
+ #FFFFFF 47%,
+ #FFFFFF 58%,
+ #A7D379 58%,
+ #A7D379 69%,
+ #3DA542 69%);
+
+}
+
+.aroace {
+ background-image: linear-gradient(180deg,
+ #ef9007 36%,
+ #f6d317 36%,
+ #f6d317 47%,
+ #FFFFFF 47%,
+ #FFFFFF 58%,
+ #45bcee 58%,
+ #45bcee 69%,
+ #1e3f54 69%);
+
+}
+
+.nb {
+ background-image: linear-gradient(180deg,
+ #FCF434 30%,
+ #FFFFFF 30%,
+ #FFFFFF 50%,
+ #9C59D1 50%,
+ #9C59D1 70%,
+ #2C2C2C 70%);
+}
+
+.nb2 {
+ background-image: linear-gradient(135deg,
+ #FCF434 30%,
+ #FFFFFF 30%,
+ #FFFFFF 50%,
+ #9C59D1 50%,
+ #9C59D1 70%,
+ #2C2C2C 70%);
+}
+
+.fluid {
+ background-image: linear-gradient(180deg,
+ #FF76A4 36%,
+ #FFFFFF 36%,
+ #FFFFFF 47%,
+ #C011D7 47%,
+ #C011D7 58%,
+ #000000 58%,
+ #000000 69%,
+ #2F3CBE 69%);
+}
+
+.queer {
+ background-image: linear-gradient(180deg,
+ #B57EDC 48%,
+ #FFFFFF 48%,
+ #FFFFFF 65%,
+ #4A8123 65%);
+}
+
+.lesbian {
+ background-image: linear-gradient(180deg,
+ #d42c00 34%,
+ #fd9855 34%,
+ #fd9855 45%,
+ #FFFFFF 45%,
+ #FFFFFF 56%,
+ #d161a2 56%,
+ #d161a2 67%,
+ #a20161 67%);
+}
+
+.agender {
+ background-image: linear-gradient(180deg,
+ #000000 30%,
+ #BCC4C7 30%,
+ #BCC4C7 38%,
+ #FFFFFF 38%,
+ #FFFFFF 46%,
+ #B7F684 46%,
+ #B7F684 54%,
+ #FFFFFF 54%,
+ #FFFFFF 62%,
+ #BCC4C7 62%,
+ #BCC4C7 70%,
+ #000000 70%);
+}
+
+.poly {
+ background-image: radial-gradient(ellipse 200% 70% at 0% 30%,
+ #FCBF00 20%,
+ #FFFFFF 20%,
+ #FFFFFF 30%,
+ #009FE3 30%,
+ #009FE3 45%,
+ #E50051 45%,
+ #E50051 60%,
+ #340C46 60%)
+}
+
+.caution {
+ background-image: linear-gradient(135deg,
+ #000000 30%,
+ #FFF000 30%,
+ #FFF000 40%,
+ #000000 40%,
+ #000000 50%,
+ #FFF000 50%,
+ #FFF000 60%,
+ #000000 60%,
+ #000000 70%,
+ #FFF000 70%);
+}
+
+@media (prefers-color-scheme: dark) {
+
+ .image-visibility {
+ -webkit-filter: invert(1);
+ filter: invert(1);
+ }
+}
+
+@media (prefers-color-scheme: light) {
+
+ .trans,
+ .bi,
+ .pan,
+ .ace,
+ .aro,
+ .aroace,
+ .gay,
+ .nb,
+ .nb2,
+ .agender,
+ .poly,
+ .fluid,
+ .queer,
+ .lesbian,
+ .caution {
+ -webkit-text-stroke: 0.01em #000;
+ }
+}
+
+@media (prefers-color-scheme: dark) {
+
+ .bi,
+ .nb,
+ .nb2,
+ .ace,
+ .aro,
+ .aroace,
+ .agender,
+ .poly,
+ .fluid,
+ .caution {
+ -webkit-text-stroke: 0.01em #fff8;
+ }
+}
+
+.pad-files {
+ border-top: 0.1em solid #60646838;
+ padding: 0.3em;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ gap: 0.3em;
+
+ @media (prefers-color-scheme: light) {
+ border-color: #0000001a;
+ }
+}
+
+.pad-file-tab {
+ display: flex;
+ gap: 0.3em;
+ padding: 0.2em 0.5em;
+ background-color: #294259;
+ border-radius: 999px;
+ cursor: pointer;
+ font-size: .75em;
+ line-height: 1em;
+
+ @media (prefers-color-scheme: light) {
+ background-color: #b3cece;
+ }
+}
+
+.pad-file-tab-close {
+ opacity: 0.5;
+
+ &:hover {
+ opacity: 1;
+ }
+}
\ No newline at end of file
diff --git a/docs/styles.css b/docs/styles.css
new file mode 100644
index 000000000..f31060294
--- /dev/null
+++ b/docs/styles.css
@@ -0,0 +1,1509 @@
+@font-face {
+ font-family: "Code Font";
+ src: url(Uiua386.ttf) format("truetype");
+}
+
+html * {
+ font-family: "Segoe UI", "Arial", sans-serif;
+}
+
+html {
+ font-size: 115%;
+ font-weight: 500;
+}
+
+body {
+ margin: 0;
+}
+
+p {
+ line-height: 1.5em;
+}
+
+h2 {
+ margin: 1.8em 0 0.5em 0;
+ padding-bottom: 0.3em;
+ border-bottom-width: 0.08em;
+ border-bottom-style: solid;
+ border-color: #888a;
+}
+
+.header {
+ position: relative;
+}
+
+a.header,
+a:visited.header,
+a:link.header {
+ text-decoration: none;
+ color: inherit;
+}
+
+a.header::before {
+ position: absolute;
+ left: -1.5em;
+ bottom: 0.4em;
+ content: "🔗";
+ opacity: 0;
+ font-size: 0.6em;
+ transition: opacity 0.2s;
+}
+
+a.header:hover::before {
+ opacity: 0.5;
+}
+
+h1>a>code,
+h2>a>code {
+ font-weight: normal;
+}
+
+button {
+ border-width: 0;
+ border-radius: 0.5em;
+ padding: 0.2em;
+ display: inline-block;
+ position: relative;
+}
+
+button:active {
+ transform: translateY(0.1em);
+}
+
+code {
+ font-family: "Code Font", monospace;
+ border-radius: 0.2em;
+ padding: 0.2em;
+ position: relative;
+ white-space: nowrap;
+}
+
+th,
+td {
+ padding: 0.3em;
+ border-radius: 0.5em;
+}
+
+th {
+ text-align: left;
+}
+
+tr:nth-child(even) {
+ background-color: #0001;
+}
+
+.bordered-table {
+ border: 0.2em solid #0005;
+ border-radius: 0.5em;
+}
+
+.header-centered-table>tr>th {
+ text-align: center;
+
+}
+
+.cell-centered-table>tr>td {
+ text-align: center;
+}
+
+li {
+ margin: 0.3em 0;
+}
+
+@media (prefers-color-scheme: dark) {
+
+ body,
+ #header-uiua,
+ .spoiler:hover {
+ color: #d1daec;
+ }
+
+ body,
+ .spoiler:hover {
+ background-color: #171d22;
+ }
+
+ #editor {
+ outline: 0.1em solid #606468;
+ background-color: #19232d;
+ }
+
+ .code,
+ .input-div,
+ input[type=text],
+ select,
+ option,
+ #settings>*>*>input,
+ #settings>*>*>select {
+ color: #d1daec;
+ background-color: #1d2c3a;
+ }
+
+ button {
+ color: #d1daec;
+ background-color: #1d2c3a;
+ }
+
+ button:hover {
+ background-color: #2d3c4a;
+ }
+
+ a:link {
+ color: #6fadea;
+ }
+
+ a:visited {
+ color: #947bec;
+ }
+
+ code {
+ background-color: #0004;
+ }
+
+ .important-button {
+ background-color: #33577b;
+ }
+
+ .important-button:hover {
+ background-color: #579;
+ }
+
+ .tutorial-nav>* {
+ background-color: #1d2c3a;
+ }
+
+ tr:nth-child(even) {
+ background-color: #0001;
+ }
+
+ .glyph-button:hover,
+ .combinator-diagram {
+ background-color: #0003;
+ }
+
+ .code-entry {
+ caret-color: white;
+ }
+
+ #subtitle {
+ color: #d1daecc0;
+ }
+}
+
+@media (prefers-color-scheme: light) {
+
+ body,
+ #header-uiua,
+ .spoiler:hover {
+ color: #344;
+ }
+
+ body,
+ .spoiler:hover {
+ background-color: #c6e7ec;
+ }
+
+ #editor {
+ background-color: #dff2f3;
+ outline: 0.1em solid #0004;
+ }
+
+ .code,
+ .input-div,
+ input[type=text],
+ select,
+ option,
+ #settings>*>*>input,
+ #settings>*>*>select {
+ color: #344;
+ background-color: #f4f6f6;
+ }
+
+ button {
+ color: #344;
+ background-color: #f6f8f8;
+ }
+
+ button:hover {
+ background-color: #fdffff;
+ }
+
+ a:link {
+ color: #0099ad;
+ }
+
+ a:visited {
+ color: #6a4bfb;
+ }
+
+ code {
+ background-color: #fff8;
+ }
+
+ .important-button {
+ background-color: #aadae0;
+ }
+
+ .important-button:hover {
+ background-color: #bee2e7;
+ }
+
+ .tutorial-nav>* {
+ background-color: #f6f8f8;
+ }
+
+ tr:nth-child(even) {
+ background-color: #fff1;
+ }
+
+ .glyph-button:hover,
+ .combinator-diagram {
+ background-color: #fffa;
+ }
+
+ .code-entry {
+ caret-color: black;
+ }
+
+ #subtitle {
+ color: #344c;
+ }
+}
+
+#top {
+ margin: 2em auto;
+ width: max(10em, min(90%, 53em));
+}
+
+#header {
+ display: flex;
+ justify-content: space-between;
+ align-items: last baseline;
+ flex-wrap: wrap;
+ gap: 1em;
+ margin-bottom: 1em;
+}
+
+
+#header-left {
+ display: flex;
+ align-items: last baseline;
+ margin: -1em 0;
+}
+
+#header-uiua {
+ text-decoration: none;
+ white-space: nowrap;
+}
+
+#subtitle {
+ margin-left: 1.5em;
+ font-size: 1em;
+ font-weight: bold;
+ font-style: italic;
+}
+
+.spoiler {
+ color: #0000;
+ background-color: #0008;
+ border-radius: 0.5em;
+}
+
+.long-subtitle {
+ font-size: 0.9em;
+}
+
+.long-subtitle>div {
+ display: flex;
+ gap: 0.5em;
+ flex-wrap: nowrap;
+ white-space: nowrap;
+}
+
+#nav {
+ display: flex;
+ gap: 1em;
+ flex-wrap: nowrap;
+ align-items: baseline;
+}
+
+#links {
+ font-size: 1.2em;
+ display: flex;
+ justify-content: center;
+ flex-wrap: wrap;
+ gap: 1em;
+ margin-bottom: 1em;
+ align-content: flex-start;
+}
+
+#links>* {
+ display: flex;
+ gap: 1em;
+ flex-wrap: wrap;
+ justify-content: space-between;
+ align-content: flex-start;
+}
+
+.main-text {
+ font-size: 120%;
+ text-align: center;
+}
+
+.wee-wuh-span {
+ font-size: 70%;
+ opacity: 0.8;
+}
+
+.features {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
+ gap: min(3em, 3vw);
+ width: min(120%, 90vw);
+ margin-left: calc(-0.5 * (min(120%, 90vw) - 100%));
+}
+
+.features>* {
+ flex: 1 1 22em;
+ width: 0;
+}
+
+#editor {
+ border-radius: 0.5em;
+ position: relative;
+}
+
+#drag-message {
+ position: absolute;
+ inset: 0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ background-color: #0008;
+ font-size: 2em;
+}
+
+#editor-wrapper {
+ margin-bottom: 0.5em;
+ font-size: min(1em, 3.5vw);
+}
+
+.small-editor {
+ font-size: 1.2em;
+}
+
+.medium-editor {
+ font-size: 1.4em;
+}
+
+#settings {
+ display: flex;
+ justify-content: space-between;
+ font-size: 0.82em;
+ padding: 0.2em;
+ gap: 0.5em;
+}
+
+#settings>* {
+ display: flex;
+ align-items: center;
+ flex-wrap: wrap;
+ gap: 0.2em 1em;
+}
+
+#settings-left {
+ width: 85%;
+ justify-content: space-between;
+}
+
+#settings-right {
+ flex-direction: column;
+ align-items: flex-end;
+}
+
+#settings>*>* {
+ display: inline-block;
+ white-space: nowrap;
+}
+
+input[type=number] {
+ appearance: textfield;
+ -moz-appearance: textfield;
+}
+
+.code-block {
+ display: block;
+ white-space: pre-wrap;
+ padding: 0.8em;
+}
+
+select,
+option,
+#settings>*>*>input,
+#settings>*>*>select {
+ border-radius: 0.5em;
+ border: none;
+ margin-left: 0.5em;
+}
+
+#settings>*>*>input[type=number] {
+ width: 3em;
+}
+
+#code-area {
+ position: relative;
+}
+
+.code-outer {
+ text-align: left;
+ border-radius: 0.5em;
+ width: 100%;
+ resize: vertical;
+ box-sizing: border-box;
+ outline: none;
+ border: none;
+ padding: 0.3em;
+ min-height: 1.8em;
+ display: flex;
+ gap: 0.1em;
+ overflow-x: auto;
+ overflow-y: hidden;
+}
+
+.code-and-overlay {
+ width: 100%;
+ position: relative;
+}
+
+.code-entry {
+ margin: 0.1em 0 0 0;
+ padding: 0;
+ position: absolute;
+ outline: none;
+ border: none;
+ box-sizing: border-box;
+ /* background-color: #0002; */
+ /* color: #0008; */
+ background-color: transparent;
+ color: transparent;
+ resize: none;
+ font-family: "Code Font", monospace;
+ font-size: inherit;
+ line-height: 1.25em;
+ overflow-wrap: normal;
+ white-space: pre;
+ overflow: hidden;
+ height: 100%;
+}
+
+.code-entry::selection {
+ color: transparent;
+ background-color: #0078d7;
+}
+
+.code-overlay {
+ margin: 0;
+ padding: 0;
+ position: absolute;
+ width: 100%;
+ pointer-events: none;
+ white-space: pre;
+}
+
+.code-line {
+ height: 1.25em;
+ padding: 0;
+ margin: 0;
+}
+
+.line-numbers {
+ min-width: 1.5em;
+}
+
+@media (prefers-color-scheme: dark) {
+ .line-numbers {
+ color: #3f4b5d;
+ }
+}
+
+@media (prefers-color-scheme: light) {
+ .line-numbers {
+ color: #bcc9ca;
+ }
+}
+
+.code-span {
+ font-size: 1em;
+ font-family: "Code Font", monospace;
+ white-space: pre;
+ text-decoration: none;
+}
+
+.code-hover {
+ display: none;
+ position: fixed;
+ font-family: "Code Font", monospace;
+ font-size: 0.7em;
+ color: #eee;
+ background-color: #000c;
+ padding: 0.2em;
+ border-radius: 0.2em;
+ pointer-events: none;
+ z-index: 1;
+ text-decoration: none;
+ white-space: pre-wrap;
+ overflow: visible;
+ -webkit-text-fill-color: #eee;
+ -moz-text-fill-color: #eee;
+}
+
+.ctrl-pressed .code-underline:hover {
+ text-decoration: underline;
+ cursor: pointer;
+}
+
+.output-frame {
+ display: flex;
+ justify-content: space-between;
+ min-height: 1.9em;
+}
+
+.output-lines {
+ overflow-x: auto;
+}
+
+.output-diagnostics {
+ white-space: pre-wrap;
+ text-align: left;
+ margin-left: 1.75em;
+ padding: 0.3em 0;
+ font-family: "Code Font", monospace;
+}
+
+.output-wrapper {
+ transform: rotateX(180deg);
+ overflow-x: auto;
+}
+
+.output {
+ white-space: pre;
+ text-align: left;
+ margin-left: 1.85em;
+ padding: 0.4em 0;
+ font-family: "Code Font", monospace;
+ transform: rotateX(180deg);
+}
+
+.output:empty,
+.output-diagnostics:empty {
+ display: none;
+}
+
+.output-item,
+.output-report {
+ font-family: inherit;
+}
+
+#code-buttons {
+ margin: 0.2em 0.2em 0.2em 0;
+ display: flex;
+ flex-wrap: nowrap;
+ right: 0;
+ max-height: 1.5em;
+}
+
+.code-button {
+ font-size: 0.9em;
+ margin: 0 0 0 0.2em;
+ height: auto;
+ text-align: center;
+ text-justify: center;
+}
+
+.important-button {
+ animation: fadeAnimation 2s infinite;
+}
+
+.output-line {
+ font-family: "Code Font", monospace;
+ font-size: inherit;
+ white-space: pre;
+}
+
+.output-wrap-line {
+ white-space: pre-wrap;
+}
+
+.output-report {
+ font-size: 0.89em;
+}
+
+.output-error {
+ color: #f44;
+}
+
+.output-warning {
+ color: #fb0;
+}
+
+.output-advice {
+ color: #2af;
+}
+
+.output-style {
+ color: #0a0;
+}
+
+.output-info {
+ color: #1cf;
+}
+
+.output-faint {
+ opacity: 0.75;
+}
+
+.output-fainter {
+ opacity: 0.55;
+}
+
+.output-media-wrapper {
+ display: flex;
+}
+
+.output-image {
+ border-radius: 0.5em;
+ max-width: 50vw;
+}
+
+.output-image-label {
+ font-size: 1em;
+ font-family: "Code Font", monospace;
+ color: white;
+ text-shadow: 0 0 0.5em black;
+ /* put the label in the corner of the image */
+ position: absolute;
+ margin-top: 0.3em;
+ margin-left: 0.4em;
+}
+
+.output-audio {
+ border-radius: 0.5em;
+ max-width: 50vw;
+}
+
+.output-audio-label {
+ font-size: 1em;
+ font-family: "Code Font", monospace;
+ margin-right: 0.5em;
+ align-self: center;
+}
+
+#code-right-side {
+ display: flex;
+ position: absolute;
+ top: 0.1em;
+ right: 0.2em;
+ padding-right: 0.3em;
+ font-size: min(1em, 3vw);
+ align-items: center;
+}
+
+#glyphs-toggle-button {
+ font-weight: bolder;
+ font-size: 0.9em;
+}
+
+#glyphs-toggle-button:hover:after {
+ font-size: 0.6em;
+}
+
+.editor-right-button {
+ font-weight: bolder;
+ opacity: 0.5;
+}
+
+.editor-right-button:hover {
+ opacity: 1;
+}
+
+.info-button:hover::after,
+.editor-right-button:hover::after,
+.experimental-icon:hover::after {
+ content: attr(data-title);
+ position: absolute;
+ font-family: "Code Font", monospace;
+ font-size: 1em;
+ left: calc(-8em - 50%);
+ bottom: 1.5em;
+ color: #eee;
+ padding: 0.2em;
+ border-radius: 0.2em;
+ pointer-events: none;
+}
+
+.editor-right-button:hover::after,
+.experimental-icon:hover::after {
+ background-color: #000b;
+ width: 8em;
+}
+
+.info-button:hover::after {
+ background-color: #000d;
+ width: 24em;
+ white-space: pre-wrap;
+ text-align: left;
+}
+
+.experimental-icon {
+ position: relative;
+}
+
+.experimental-icon:hover::after {
+ left: 100% !important;
+ bottom: 0 !important;
+}
+
+#example-tracker {
+ margin-left: 0.5em;
+ font-size: 0.8em;
+}
+
+.glyph-buttons {
+ padding: 0.1em;
+ font-size: 1.4em;
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-evenly;
+ align-items: baseline;
+}
+
+.glyph-button {
+ font-family: "Code Font", monospace;
+ font-size: 0.84em;
+ padding: 0.045em;
+ margin: 0em;
+ background-color: transparent;
+}
+
+.glyph-button:hover::after {
+ content: attr(data-title);
+ position: absolute;
+ font-family: "Code Font", monospace;
+ font-size: 0.7em;
+ bottom: 100%;
+ color: #eee;
+ background-color: #000a;
+ padding: 0.1em;
+ border-radius: 0.2em;
+ left: -1em;
+ width: 7em;
+ pointer-events: none;
+ z-index: 1;
+ white-space: pre-wrap;
+ -webkit-text-fill-color: #eee;
+ -moz-text-fill-color: #eee;
+}
+
+.experimental-glyph-button {
+ display: none;
+}
+
+.format-button {
+ display: none;
+}
+
+.run-format-button:hover::after {
+ content: attr(data-title);
+ position: absolute;
+ font-family: "Code Font", monospace;
+ font-size: 0.8em;
+ bottom: 110%;
+ right: 0%;
+ color: #eee;
+ background-color: #000a;
+ padding: 0.1em;
+ border-radius: 0.2em;
+ pointer-events: none;
+ z-index: 2;
+ white-space: pre;
+ -webkit-text-fill-color: #eee;
+ -moz-text-fill-color: #eee;
+}
+
+.prim-code-a {
+ text-decoration: none;
+ white-space: nowrap;
+}
+
+.prim-glyph {
+ font-weight: 400;
+}
+
+.prim-code:hover::after {
+ content: attr(data-title);
+ position: absolute;
+ font-family: "Code Font", monospace;
+ font-size: 0.8em;
+ bottom: 100%;
+ color: #eee;
+ background-color: #000d;
+ padding: 0.2em;
+ border-radius: 0.2em;
+ left: 0;
+ pointer-events: none;
+ width: 10em;
+ text-decoration: none;
+ white-space: pre-wrap;
+ overflow: visible;
+ line-height: 1em;
+ z-index: 1;
+ -webkit-text-fill-color: #eee;
+ -moz-text-fill-color: #eee;
+}
+
+.glyph-doc {
+ position: absolute;
+ top: min(10%, 1em);
+ left: 10%;
+ padding: 0.5em;
+ font-size: 0.75em;
+ border-radius: 0.5em;
+ max-width: 80%;
+ white-space: pre-wrap;
+ font-family: "Code Font", monospace;
+ z-index: 1;
+}
+
+.additional-functions {
+ font-family: "Code Font", monospace;
+ align-self: center;
+ font-size: 0.7em;
+ width: 1.1em;
+ white-space: pre;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ margin-left: 0;
+ margin-right: 0;
+ text-align: center;
+}
+
+.additional-functions::-ms-expand {
+ display: none;
+}
+
+.additional-functions>* {
+ font-family: "Code Font", monospace;
+}
+
+.named-function-button {
+ font-family: "Code Font", monospace;
+ white-space: pre;
+ text-align: left;
+}
+
+@media (prefers-color-scheme: dark) {
+
+ .glyph-doc {
+ background-color: #000c;
+ }
+
+ .glyph-doc-ctrl-click {
+ color: #aaa;
+ }
+}
+
+@media (prefers-color-scheme: light) {
+
+ .glyph-doc {
+ background-color: #fffd;
+ }
+
+ .glyph-doc-ctrl-click {
+ color: #777;
+ }
+}
+
+.glyph-doc-ctrl-click {
+ font-size: 0.7em;
+}
+
+.code-font {
+ font-family: "Code Font", monospace;
+}
+
+.combinator-diagram {
+ border-radius: 0.5em;
+ height: 8em;
+}
+
+@media (prefers-color-scheme: dark) {
+ .stack-function {
+ color: #d1daec;
+ }
+}
+
+@media (prefers-color-scheme: light) {
+ .stack-function {
+ color: #344;
+ }
+}
+
+.private-binding>* {
+ opacity: 0.75;
+}
+
+.module {
+ color: #d7be8c;
+}
+
+.noadic-function {
+ color: #ed5e6a;
+}
+
+.monadic-function {
+ color: #95d16a;
+}
+
+.dyadic-function {
+ color: #54b0fc;
+}
+
+.triadic-function {
+ color: #8078f1;
+}
+
+.tetradic-function {
+ color: #f576d8;
+}
+
+.variadic-function {
+ background-image: linear-gradient(170deg,
+ #ed5e6a 34%,
+ #95d16a 34%,
+ #95d16a 45%,
+ #54b0fc 45%,
+ #54b0fc 56%,
+ #8078f1 56%,
+ #8078f1 67%,
+ #f576d8 67%);
+}
+
+.monadic-modifier {
+ color: #f0c36f;
+}
+
+.dyadic-modifier {
+ color: #cc6be9;
+}
+
+.triadic-modifier {
+ color: #F5A9B8
+}
+
+.space-character {
+ border-width: 2px;
+ border-radius: 0.3em;
+ border-style: dashed;
+ margin: 0 -2px;
+}
+
+@media (prefers-color-scheme: dark) {
+ .string-literal-span {
+ color: #20f9fc;
+ }
+
+ .space-character {
+ border-color: #20f9fc80;
+ }
+
+ .strand-span {
+ color: #fff8;
+ }
+}
+
+@media (prefers-color-scheme: light) {
+ .string-literal-span {
+ color: #1c9;
+ }
+
+ .space-character {
+ border-color: #1c98;
+ }
+
+ .strand-span {
+ color: #0008;
+ }
+}
+
+.number-literal {
+ color: #f85;
+}
+
+
+.comment-span {
+ color: #888;
+}
+
+.value-hint {
+ color: #8888;
+}
+
+@media (prefers-color-scheme: dark) {
+ .output-a {
+ color: #cff;
+ }
+
+ .output-b {
+ color: #ccf;
+ }
+
+ .output-c {
+ color: #fcf;
+ }
+
+ .output-d {
+ color: #fcc;
+ }
+
+ .output-e {
+ color: #ffc;
+ }
+
+ .output-f {
+ color: #cfc;
+ }
+}
+
+@media (prefers-color-scheme: light) {
+
+ .output-a {
+ color: #225;
+ }
+
+ .output-b {
+ color: #525;
+ }
+
+ .output-c {
+ color: #522;
+ }
+
+ .output-d {
+ color: #552;
+ }
+
+ .output-e {
+ color: #252;
+ }
+
+ .output-f {
+ color: #255;
+ }
+}
+
+#editor-help {
+ margin: 0.4em 0 0 0;
+ font-size: 1em;
+ opacity: 0.5;
+ display: flex;
+ justify-content: space-between;
+ gap: 0.5em;
+}
+
+#editor-help:empty {
+ display: none;
+}
+
+#editor-help>* {
+ line-height: 1em;
+ margin: 0;
+ white-space: pre-wrap;
+}
+
+.sound-button {
+ background-color: transparent;
+}
+
+.tutorial-nav {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ font-size: 1.1em;
+ gap: 0.5em;
+}
+
+.tutorial-nav>* {
+ border-radius: 0.5em;
+ border-color: #0003;
+ border-radius: 0.5em;
+ padding: 0.5em;
+}
+
+.tutorial-nav>*:empty {
+ background-color: #0000;
+}
+
+.primitive-list {
+ display: flex;
+ flex-wrap: wrap;
+ flex-direction: column;
+}
+
+.primitive-list>* {
+ margin-bottom: 0.5em;
+}
+
+#ascii-glyphs {
+ display: flex;
+ justify-content: space-evenly;
+ flex-wrap: wrap;
+}
+
+.input-div {
+ display: flex;
+ align-items: center;
+ font-size: 1em;
+ border-radius: 0.5em;
+ padding: 0.5em;
+ width: min(100%, max(30%, 22em));
+}
+
+input[type=text] {
+ font-size: 1em;
+ border-radius: 0.5em;
+ padding: 0 0.5em;
+ outline: none;
+ border: none;
+ width: 100%;
+}
+
+#function-search {
+ scroll-margin-top: 1em;
+ scroll-margin-bottom: 1em;
+}
+
+#function-search-wrapper {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.const-desc {
+ display: inline-block;
+ white-space: pre-wrap;
+}
+
+.running-text {
+ animation: fadeAnimation 1s infinite;
+}
+
+.slow-pulse {
+ animation: pulseAnimation 2s infinite;
+}
+
+@keyframes fadeAnimation {
+
+ 0%,
+ 100% {
+ opacity: 0.5;
+ }
+
+ 50% {
+ opacity: 1;
+ }
+}
+
+
+@keyframes pulseAnimation {
+
+ 0%,
+ 100% {
+ transform: scale(1) translate(0);
+ }
+
+ 50% {
+ transform: scale(1, 1.1) translate(0, -0.05em);
+ }
+}
+
+.uiuism-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.pls-no-block {
+ font-size: 0.7em;
+}
+
+a.clean {
+ text-decoration: none;
+}
+
+.experimental {
+ color: #db2;
+}
+
+.text-gradient {
+ background-size: 100%;
+ background-clip: text;
+ -webkit-background-clip: text;
+ -moz-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ -moz-text-fill-color: transparent;
+}
+
+.trans {
+ background-image: linear-gradient(180deg,
+ #5BCEFA 34%,
+ #F5A9B8 34%,
+ #F5A9B8 45%,
+ #FFFFFF 45%,
+ #FFFFFF 56%,
+ #F5A9B8 56%,
+ #F5A9B8 67%,
+ #5BCEFA 67%);
+}
+
+.bi {
+ background-image: linear-gradient(180deg,
+ #D60270 45%,
+ #9B4F96 45%,
+ #9B4F96 64%,
+ #0038A8 64%);
+}
+
+.pan {
+ background-image: linear-gradient(180deg,
+ #FF218C 45%,
+ #FFD800 45%,
+ #FFD800 64%,
+ #21B1FF 64%);
+}
+
+.gay {
+ background-image: linear-gradient(180deg,
+ #E40303 30%,
+ #FFA52C 30%,
+ #FFA52C 40%,
+ #FFFF41 40%,
+ #FFFF41 50%,
+ #008018 50%,
+ #008018 60%,
+ #0000F9 60%,
+ #0000F9 70%,
+ #86007D 70%);
+}
+
+.ace {
+ background-image: linear-gradient(180deg,
+ #000000 30%,
+ #A3A3A3 30%,
+ #A3A3A3 50%,
+ #FFFFFF 50%,
+ #FFFFFF 70%,
+ #800080 70%);
+}
+
+.aro {
+ background-image: linear-gradient(180deg,
+ #000000 36%,
+ #A9A9A9 36%,
+ #A9A9A9 47%,
+ #FFFFFF 47%,
+ #FFFFFF 58%,
+ #A7D379 58%,
+ #A7D379 69%,
+ #3DA542 69%);
+
+}
+
+.aroace {
+ background-image: linear-gradient(180deg,
+ #ef9007 36%,
+ #f6d317 36%,
+ #f6d317 47%,
+ #FFFFFF 47%,
+ #FFFFFF 58%,
+ #45bcee 58%,
+ #45bcee 69%,
+ #1e3f54 69%);
+
+}
+
+.nb {
+ background-image: linear-gradient(180deg,
+ #FCF434 30%,
+ #FFFFFF 30%,
+ #FFFFFF 50%,
+ #9C59D1 50%,
+ #9C59D1 70%,
+ #2C2C2C 70%);
+}
+
+.nb2 {
+ background-image: linear-gradient(135deg,
+ #FCF434 30%,
+ #FFFFFF 30%,
+ #FFFFFF 50%,
+ #9C59D1 50%,
+ #9C59D1 70%,
+ #2C2C2C 70%);
+}
+
+.fluid {
+ background-image: linear-gradient(180deg,
+ #FF76A4 36%,
+ #FFFFFF 36%,
+ #FFFFFF 47%,
+ #C011D7 47%,
+ #C011D7 58%,
+ #000000 58%,
+ #000000 69%,
+ #2F3CBE 69%);
+}
+
+.queer {
+ background-image: linear-gradient(180deg,
+ #B57EDC 48%,
+ #FFFFFF 48%,
+ #FFFFFF 65%,
+ #4A8123 65%);
+}
+
+.lesbian {
+ background-image: linear-gradient(180deg,
+ #d42c00 34%,
+ #fd9855 34%,
+ #fd9855 45%,
+ #FFFFFF 45%,
+ #FFFFFF 56%,
+ #d161a2 56%,
+ #d161a2 67%,
+ #a20161 67%);
+}
+
+.agender {
+ background-image: linear-gradient(180deg,
+ #000000 30%,
+ #BCC4C7 30%,
+ #BCC4C7 38%,
+ #FFFFFF 38%,
+ #FFFFFF 46%,
+ #B7F684 46%,
+ #B7F684 54%,
+ #FFFFFF 54%,
+ #FFFFFF 62%,
+ #BCC4C7 62%,
+ #BCC4C7 70%,
+ #000000 70%);
+}
+
+.poly {
+ background-image: radial-gradient(ellipse 200% 70% at 0% 30%,
+ #FCBF00 20%,
+ #FFFFFF 20%,
+ #FFFFFF 30%,
+ #009FE3 30%,
+ #009FE3 45%,
+ #E50051 45%,
+ #E50051 60%,
+ #340C46 60%)
+}
+
+.caution {
+ background-image: linear-gradient(135deg,
+ #000000 30%,
+ #FFF000 30%,
+ #FFF000 40%,
+ #000000 40%,
+ #000000 50%,
+ #FFF000 50%,
+ #FFF000 60%,
+ #000000 60%,
+ #000000 70%,
+ #FFF000 70%);
+}
+
+@media (prefers-color-scheme: dark) {
+
+ .image-visibility {
+ -webkit-filter: invert(1);
+ filter: invert(1);
+ }
+}
+
+@media (prefers-color-scheme: light) {
+
+ .trans,
+ .bi,
+ .pan,
+ .ace,
+ .aro,
+ .aroace,
+ .gay,
+ .nb,
+ .nb2,
+ .agender,
+ .poly,
+ .fluid,
+ .queer,
+ .lesbian,
+ .caution {
+ -webkit-text-stroke: 0.01em #000;
+ }
+}
+
+@media (prefers-color-scheme: dark) {
+
+ .bi,
+ .nb,
+ .nb2,
+ .ace,
+ .aro,
+ .aroace,
+ .agender,
+ .poly,
+ .fluid,
+ .caution {
+ -webkit-text-stroke: 0.01em #fff8;
+ }
+}
+
+.pad-files {
+ border-top: 0.1em solid #60646838;
+ padding: 0.3em;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ gap: 0.3em;
+
+ @media (prefers-color-scheme: light) {
+ border-color: #0000001a;
+ }
+}
+
+.pad-file-tab {
+ display: flex;
+ gap: 0.3em;
+ padding: 0.2em 0.5em;
+ background-color: #294259;
+ border-radius: 999px;
+ cursor: pointer;
+ font-size: .75em;
+ line-height: 1em;
+
+ @media (prefers-color-scheme: light) {
+ background-color: #b3cece;
+ }
+}
+
+.pad-file-tab-close {
+ opacity: 0.5;
+
+ &:hover {
+ opacity: 1;
+ }
+}
\ No newline at end of file
diff --git a/docs/text/code_tactility.md b/docs/text/code_tactility.md
new file mode 100644
index 000000000..d13b460be
--- /dev/null
+++ b/docs/text/code_tactility.md
@@ -0,0 +1,121 @@
+# Code Tactility
+
+One of the strengths of interpreted programming languages, and array languages in particular, is their high level of interactivity. It is very easy to experiment with code, moving data and functions around to get a better sense of the solution to a problem.
+
+This exercise can be likened to "feeling" the code, turning it around in your hand, poking it, prodding it, inspecting it.
+
+This section covers a few tools that Uiua provides for making code easier to work with and debug.
+
+## [stack]()
+
+Uiua already prints out any values left on the stack when the program ends. This is usually enough for smaller programs, but sometimes, you need to be able to see what values are on the stack somewhere in the middle of the code.
+
+[stack]() was mentioned near the [beginning](/tutorial/basic#stack) of this tutorial. It prints out values from the stack without removing them. Subscripting [stack]() prints out only that many values.
+
+```uiua
+5 ? 1 [2 3] "uiua"
+```
+
+```uiua
+5 1 ?₁ ⇡3 "uiua"
+```
+As you can see, the line and column number is also printed.
+
+The formatter will convert multiple `?`s that come immediately after [stack]() a subscript. Try it below.
+
+```uiua
+??? √5 7 10
+```
+
+[stack]() will show you the boundaries of the functions that values are used in.
+
+```uiua
+G ← /+?⇡
+F ← ×G
+F 10 4
+```
+
+[stack]() llows you to inspect the stack at a given place in the code. It makes it easy to get a quick sense of what values a function is working with.
+
+## Labels
+
+Labels allow you to tag an array with a debug-only name. They are written with a `$` immediately followed by an identifier.
+
+```uiua
+$Numbers [1 2 3]
+```
+
+Labels are *only* visible in debugging outputs. This includes normal interpreter output as well as [stack]().
+
+Labels will *not* be shown when arrays are formatted using [`&p`]() or format strings.
+
+```uiua
+&p $"--_--" . $TheThing ⇡5
+```
+
+You can easily label multiple values with [bracket]().
+
+```uiua
+⊓$Foo$Bar °⊂ [2 3 5 7]
+```
+
+Labeled arrays cannot be put into arrays together unless they are boxed.
+
+```uiua
+[$a 1 $b 2 $c 3] # Wrong
+```
+```uiua
+{$a 1 $b 2 $c 3} # Right
+```
+
+Labels are nice for keeping track of different values as they move around the stack.
+
+It is not possible to retrieve the label of a value using code. Labels are only for debugging, not for carrying data.
+
+## Line Manipulation
+
+Uiua running code right-to-left has a couple unfortunate side effects when it comes to editing. The first you're likely to run into is having to constantly press the `←` key on your keyboard to move the cursor to the left.
+
+If you type a `;` character, the formatter will flip the current line across it. This allows you to enter code in the same order it is executed.
+
+```uiua
+⇡12;↯3_4 # Format to flip!
+```
+
+You can put many `;`s on the same line.
+```uiua
+1;2;3;4
+```
+
+Another problems is that if you want to split a line of code into two lines, it is not enough to simply place your cursor at the split point and press Enter, as this puts the lines in the wrong order!
+
+Instead, you can type `;;` at the point you want to split the code. Upon formatting, the line will be split in a way that preserves the same meaning!
+
+```uiua
+↥⊸⇌;;⊞=.⇡5 # Format to split!
+```
+
+You can put as many of these splitters in your code as you like, and the formatter will handle them all at once.
+
+```uiua
+"lines";;"the";;"all";;"Split"
+```
+
+If used in a binding, the code will be wrapped in `()`s.
+
+```uiua
+F ← ⁅∵⋅⚂;;↯⟜⊚ # Format it!
+F 5
+```
+
+Putting a splitter at the beginning or end of a line will *join* lines rather than splitting them.
+
+```uiua
+1 2
+;3 4
+```
+
+```uiua
+"Oh";
+"boy!"
+```
diff --git a/docs/text/design.md b/docs/text/design.md
new file mode 100644
index 000000000..f7ee8f657
--- /dev/null
+++ b/docs/text/design.md
@@ -0,0 +1,109 @@
+# Design
+
+This page explains the reasons for some of Uiua's design decisions.
+It serves as a [defense of design](https://news.knowledia.com/US/en/articles/more-software-projects-need-defenses-of-design-85ea9e23ffd85f5fde5a2d3d42001393cbce169a).
+
+## Stack Basing
+
+### Combinators
+
+When I first started developing Uiua, it was neither stack-based nor array-oriented. What it *did* focus a lot on was *combinators*. I had this whole hierarchy of language-level operators that let you construct arbitrarily complex combinators relatively succinctly.
+I discovered what a lot of others have discovered when delving deep into tacit code: it's really hard to read and write and reason about.
+
+Eventually, I moved to a stack-based model and discovered that you can write almost any 1 or 2 argument combinator with just [`duplicate`](/docs/duplicate), [`over`](/docs/over), and [`flip`](/docs/flip).
+Of course, I also made the discovery that juggling 3 or more values on the stack also imposes a high cognitive load on the developer. This is especially true if you try to *rotate* the stack like you could with the now-removed functions `roll` and `unroll`. [`dip`](/docs/dip) replaced the rolling functions as it is more general and easier to reason about, and eventually grew into [Planet Notation](/tutorial/advancedstack#planet-notation).
+
+As more and more Uiua code was written, I developed the principle of [Stack-Source Locality](/tutorial/tacitcode#stack-source-locality) to guide readability. The [`on`](/docs/on) and [`by`](/docs/by) modifiers were added to express common patterns of stack manipulation.
+
+### Expressions
+
+Long tacit expressions in most array languages can get very unwieldy. Because binary operations are infix, you have to parse the tree structure in your head before you can start determining the order of operations.
+
+For example, in BQN, you can trim matches from the beginning of a string with [`x(∧`∘∊˜¬⊸/⊢)y`](https://mlochbaum.github.io/bqncrate/?q=Remove%20cells%20that%20appear%20in%20x%20from%20beginning%20of%20y#).
+
+In contrast, here is their equivalent in Uiua, implemented the same way:
+
+```uiua
+Trim ← ▽¬\×⊸∈
+```
+
+You'll notice that stack basing simplifies the expression in a few ways:
+
+- There is no Uiua code corresponding to the BQN combinator `∘`. Function composition is implicit.
+- Functions are executed right-to-left instead of in a tree ordering.
+- The expression does not require `()`. In fact, no Uiua expression requires explicit grouping. `()` is used to make inline functions instead.
+
+I think this clarity makes writing long tacit expressions much more workable.
+
+## The Array Model
+
+Uiua's array model went through a lot of iterations during development. At first, it used a flat, vector-based model ala K and Q. Then, I switched to BQN's Based array model. That was really complicated to implement primitives for, so I tried something else.
+
+I switched to a flat array model with "fill elements". While arrays could not be nested, operations which would create nested arrays in other languages would instead create jagged arrays with special fill elements at the end of some rows. While this worked, the code was scattered everywhere with checks for fill elements, because they had to propagate through everything. It also had the unfortunate effect of making byte arrays take up 2 bytes of space, since a bit had to be used to indicate whether the byte was a fill element or not. Also, a lot of operations, such as [`transpose`](/docs/transpose), don't really make a lot of sense with jagged arrays.
+
+Finally, I switched to the current model, which resembles J's Boxed array model. While you can do something resembling J's `box <` using [`box`](/docs/box) (and `open >` with [`un`](/docs/un)[`box`](/docs/box)), I designed functions like [`partition`](/docs/partition) and [`group`](/docs/group) to allow selecting uniformly-shaped rows from a non-uniform list in an effort to minimize interaction with jagged data.
+
+The fact that the stack is always available also makes putting non-uniform data in arrays less necessary.
+
+## The Glyphs
+
+Most of Uiua's glyphs were chosen for one of a few reasons:
+
+- It is a common mathematical symbol, such as [`add`](/docs/add), [`subtract`](/docs/subtract), and [`pi`](/docs/pi).
+- It is a very commonly used function and should create little line noise, such as [`duplicate`](/docs/duplicate) and [`flip`](/docs/flip).
+- It is used in other array languages, such as [`reduce`](/docs/reduce), [`scan`](/docs/scan), and [`transpose`](/docs/transpose).
+- It kind of reminds me of what it does. Some of my favorites are [`table`](/docs/table), [`reshape`](/docs/reshape), [`rotate`](/docs/rotate), [`deshape`](/docs/deshape), and [`find`](/docs/find).
+- Its function is kind of abstract, but there are other related functions, so they all use related glyphs. For example, [`fold`](/docs/fold) has this nice symmetry with [`reduce`](/docs/reduce) and [`scan`](/docs/scan). The indexing/finding/grouping functions like[`classify`](/docs/classify), [`group`](/docs/group), [`deduplicate`](/docs/deduplicate), etc are all circles.
+- Circles and squares look nice, such as with [`where`](/docs/where) and [`pick`](/docs/pick).
+- I think they look like cute little guys: [`assert`](/docs/assert) and [`try`](/docs/try).
+
+## No Local Variables
+
+Forbidding general local variables has a few benefits:
+
+- I don't have to implement them (score!)
+- It forces you to write (often beautiful) tacit code, which I would argue Uiua enables better than almost any other programming language.
+- It frees you from the burden of naming things.
+- Because values only exist on the stack as long as they are needed, memory is allocated, reused, and collected in an efficient way.
+
+## Identifiers and Formatting
+
+I made the decision to have a formatter that turns names into Unicode glyphs about as soon as I started using Unicode glyphs. I did not want to require special keyboard or editor support like APL and BQN do.
+
+The advantage of a file-watching formatter is that the only feature your editor needs is the ability to automatically reload files if they change on disk. You don't need special keybinds or plugins or anything.
+
+The other nice thing about a formatter is that it makes it easier to get started with the language. You do not have to memorize a bunch of keyboard shortcuts to type the glyphs. You just need to learn their names.
+
+## Inverses
+
+I originally added [`un`](/docs/un) (originally `invert`) and [`under`](/docs/under) because they were useful-seeming constructs that existed in the other array languages. Little did I know that they would come to be such a central pillar of Uiua's design.
+
+Members of the Uiua community have always pushed for more inverses, I think to the language's great benefit. [`anti`](/docs/anti) was eventually added as an inversion modifier that captured an increasingly useful inversion pattern.
+
+## Inspiration
+
+### BQN
+
+The main language that inspired Uiua is [BQN](https://mlochbaum.github.io/BQN/). While I had heard about APL before, BQN was my first real exposure to the power of the array paradigm. I think the language is an astounding feat of engineering. Marshall is both a genius and a great communicator.
+
+However, as you can read above, a lot of Uiua's design decisions are responses to things I *didn't* like about BQN. There were a bunch of little pain-points that I thought I could improve on.
+
+A lot of the behavior of Uiua's built-in functions (and the choice of which built-ins to include) is inspired by BQN's primitives. Just a few examples are [`transpose`](/docs/transpose), [`classify`](/docs/classify), [`group`](/docs/group), and [`take`](/docs/take).
+
+Another thing that was largely inspired by BQN is this website! BQN's site is excellent. I really like the way it is organized and the way it presents the language. I particularly liked the built-in editor, so I made my own version for Uiua that has syntax highlighting and history, which I reuse in all the tutorials and examples.
+
+### APL
+
+Being the oldest array language, APL has had a lot of time to develop good ideas, particularly for the behavior of primitives.
+
+Uiua's behaviors for [`orient`](/docs/orient), [`windows`](/docs/windows), and [`partition`](/docs/partition) are inspired by APL's.
+
+### J
+
+Uiua uses basically the same array model as J: flat arrays with a box type. The main difference is that Uiua allows some functions, particularly pervasive ones, to implicitly penetrate boxes.
+
+### The Array Cast
+
+During the period of Uiua's development, I spent a lot of time listening to [The Array Cast](https://arraycast.com/), a podcast about array languages. The conversations about the design and implementation of APL, J, K, Q, and BQN are both inspirational and informative. The guys have such a depth and breadth of knowledge on the topic. I really recommend giving it a listen.
+
+Thanks to [Con](https://github.com/codereport)[or](https://www.youtube.com/@code_report), Bob, Stephen, Adám, [Marshall](https://github.com/mlochbaum), Richard, and all the guests.
diff --git a/docs/text/experimental.md b/docs/text/experimental.md
new file mode 100644
index 000000000..1b6321ab0
--- /dev/null
+++ b/docs/text/experimental.md
@@ -0,0 +1,228 @@
+## Inline Macros
+
+Following an inline function's `()`s with one or more `!`s will make it an inline index macro.
+This allows `^` placeholders to be used inside the function.
+
+```uiua
+# Experimental!
+(^0^0)!↯ 2 3 4
+```
+
+```uiua
+# Experimental!
+StdDev ← √(^0^1^0)‼(÷⧻⟜/+|×.-).
+StdDev [1 2 3 4]
+```
+
+An inline code macro can be specified by putting a `^` between the `)` and the first `!`.
+
+```uiua
+# Experimental!
+(⇌)^‼(⊂1|⊂2) []
+```
+
+```uiua
+# Experimental!
+($"_ ← 5"⊢)^!X
+X
+```
+
+```uiua
+# Experimental!
+(⋅⊢)^!+
+(⋅⊢)^!⊓+¯
+```
+
+## [derivative](/docs/derivative) and [integral](/docs/integral)
+
+These modifiers transform a mathematical expression.
+
+Currently, only polynomials are supported.
+
+```uiua
+# Experimental!
+∂(×.) 5 # x² → 2x
+∂√ 1/9 # √x → 1/(2√x)
+∂(-4+⊃(ⁿ2|ׯ2)) [0 1 2] # x² - 2x - 4 → 2x² - 2x
+```
+
+```uiua
+# Experimental!
+∫(×.) 3 # x² → x³/3
+∫√ 1 # √x → (2x^1.5)/3
+∫(+5×2) 2 # 2x + 5 → x² + 5x
+```
+
+## Data Definitions
+
+Data definitions allow you to define structured data whose fields can be accessed by name.
+
+The most basic way to define a data definition is with a `~` followed by a name and some field names inside stack array syntax.
+
+```uiua
+# Experimental!
+~MyData {Foo Bar}
+```
+
+This generates a [module](/tutorial/modules) with a constructor as well as field accessors for the given names.
+
+The constructor has the name `New`, which allows it to be called with the module's name.
+
+```uiua
+# Experimental!
+~MyData {Foo Bar}
+MyData "wow!" 5
+MyData~Bar .
+```
+
+Notice that the created structure is just a normal box array. The values of the fields are [label](/tutorial/codetactility#labels)led with their name.
+
+The field accessors both [un](/docs/un)[box](/docs/box) and un-label the retrieved values.
+
+If `[]`s are used instead of `{}`s, the fields will not be boxed or labelled.
+
+```uiua
+# Experimental!
+~Color [r g b a]
+Color 1 0.5 0 1
+```
+
+The field accessors can be used with [under](/docs/under) modify or replace the value.
+
+```uiua
+# Experimental!
+~MyData {Foo Bar}
+MyData "wow" 5
+⍜MyData~Bar(+1) .
+⍜MyData~Foo⋅"cool"
+```
+
+The [un](/docs/un)[by](/docs/by) idiom also allows you to easily set a value.
+
+```uiua
+# Experimental!
+~MyData {Foo Bar}
+MyData "wow" 5
+°⊸MyData~Foo "cool"
+```
+
+You can set an initial value for a field by writing it like a binding.
+
+```uiua
+# Experimental!
+~MyData {Foo Bar ← 0}
+MyData 5
+```
+
+The initializer can be a function. This will pre-process the value before construction.
+
+Multiple initialized fields can be separated by newlines or `|`s.
+
+```uiua
+# Experimental!
+~MyData {Foo ← ⊂5⇌|Bar ← 0}
+MyData 1_2_3
+```
+
+You can also add validation functions to a field. This function will be called both upon construction (after the initializer) and upon mutation.
+
+The function should come after the name and a `:`, but before the initializer.
+
+A common use case for this is to validate the type of a field.
+
+```uiua should fail
+# Experimental!
+~MyData {Foo: °0type|Bar: °1type}
+MyData 1 "hi" # Works
+MyData 3 5 # Fails
+```
+
+```uiua should fail
+# Experimental!
+~MyData {Foo: °0type|Bar: °1type}
+MyData 1 "hi"
+°⊸MyData~Bar 5
+```
+
+You can put a data definition inside a scoped module if you'd like to define other functions that use the data. If the name is omitted, the name of the module will be used.
+
+```uiua
+# Experimental!
+┌─╴MyData
+ ~{Foo Bar}
+ Format ← /$"Foo is _ and Bar is _"
+└─╴
+MyData~Format MyData 1_2_3 5
+```
+
+If instead of a `~`, you use a `|` followed by a name, the data definition will be treated as a *variant* of the enclosing module.
+
+The constructors for these variants will prepend a tag to the data so that they can be disambiguated. The field accessors will skip the tag.
+
+Because the constructed variants are tagged with incrementing integers, they can be [pattern-matched](/tutorial/patternmatching) on, perhaps in [try](/docs/try).
+
+Variants may be empty.
+
+```uiua
+# Experimental!
+┌─╴M
+ |Foo {Bar Baz}
+ |Qux [x y z]
+ |Sed {M N}
+ |Wir
+
+ Format ← ⍣(
+ $"_ and _" °Foo
+ | $"⟨_ _ _⟩" °Qux
+ | $"_: _" °Sed
+ | "Wir!" °Wir
+ )
+└─╴
+M~Format M~Foo 2 5
+M~Format M~Qux 0 4 1
+M~Format M~Sed "Name" "Dan"
+M~Format M~Wir
+```
+
+A data definition's name can be used as a monadic macro. The field getters will be in scope inside the macro.
+
+```uiua
+# Experimental!
+~MyData {Foo Bar}
+MyData!(+⊃Foo Bar New) 3 5
+```
+
+A `Fields` item is generated which contains the field names as boxed strings.
+```uiua
+# Experimental!
+~Foo {Bar Baz Qux}
+Foo~Fields
+```
+
+If some code immediately follows the data definition, a `Call` function will be generated which uses the constructor as a [fill](/docs/fill) function and in which the field names pull from the fill value.
+
+This is called a *data function* and essentially allows for named function arguments.
+
+```uiua
+# Experimental!
+~MyData {Foo Bar} ↯2 Foo_Foo_Bar
+MyData 3 5
+```
+
+You can mix and match accessed fields and normal function inputs.
+
+```uiua
+# Experimental!
+~Foo [x] +x
+Foo 3 5
+```
+
+```uiua
+# Experimental!
+~Quad [a b c] ÷×2a -b ⊟¯.√ℂ0 -/×4_a_c ×.b
+Quad 1 ¯3 2
+```
+
+Note that in general, functions should not be written this way. Keeping an array as a [fill](/docs/fill) value means it will be duplicated if it is mutated, which is inefficient.
+
+Data functions are mainly useful when your function has a lot of configuration parameters. Arrays that are the primary thing being transformed, as well as arrays that are potentially large, should be kept on the stack.
\ No newline at end of file
diff --git a/docs/text/files_and_streams.md b/docs/text/files_and_streams.md
new file mode 100644
index 000000000..4757a0b5a
--- /dev/null
+++ b/docs/text/files_and_streams.md
@@ -0,0 +1,104 @@
+# Files and Streams
+
+Uiua has support for reading and writing files from the filesystem. It has helper functions for reading and writing entire files, as well as a stream abstraction for processing files in chunks. This stream abstraction extends to other input/output sources, such as network sockets.
+
+## Reading and Writing Entire Files
+
+Loading an entire file into an array is very simple.
+For demonstration purposes, this website has a built-in file called `example.txt` that we will work with.
+
+We can read an entire file as a string with [`&fras`]() (file read all string).
+
+```uiua
+&fras "example.txt"
+```
+
+If we instead want to read the file into an array of bytes, we can use [`&frab`]() (file read all bytes).
+
+```uiua
+&frab "example.txt"
+```
+
+To write an entire array to a file, we can use [`&fwa`]() (file write all). The type of the array determines whether the file is written as text or binary.
+
+```uiua
+&fwa "file.txt" "Hello, world!"
+```
+
+Each editor on this site has a virtual file system, which means that we can read from files after they have been written to. This is useful for testing file writing functions.
+
+```uiua
+&fwa "file.bin" ⇡10
+&frab "file.bin"
+```
+
+## Streams
+
+Stream are an abstraction for sending and receiving data in chunks from some source. Similar concepts exist in many programming languages, inluding Uiua.
+
+In this tutorial, we will focus on using streams to interact with files. However, Uiua also uses streams for other input/output sources, particularly network sockets.
+
+## Reading Streams
+
+Streams in Uiua are passed around as *handles* - boxed integer values that can be used to look up the stream in the interpreter. Functions that create streams return these handles, and they attach some metadata about what kind of stream it is for debugging purposes.
+
+We can use [`&fo`]() (file open) to open a file for reading. This function returns a stream handle.
+
+```uiua
+&fo "example.txt"
+```
+
+There are a few functions for reading from streams. The most basic two are [`&rs`]() (read string) and [`&rb`]() (read bytes). These functions read at most a certain number of bytes from the stream and return them as a character or byte array, respectively.
+
+Here, we open a file with [`&fo`]() and then read 10 bytes from it. [`&rb`]() simply puts the bytes in an array, while [`&rs`]() converts them to a string.
+```
+&rb 10 &fo "example.txt"
+&rs 10 &fo "example.txt"
+```
+
+If we pass [`infinity`]() as the number of bytes to read, the stream will read until the end of the file. This is functionally equivalent to [`&fras`]() or [`&frab`]().
+
+```uiua
+&rs ∞ &fo "example.txt"
+```
+
+If we want to read up until some delimiter, we can use [`&ru`]() (read until). This function reads from the stream until it encounters a certain sequence of characters or bytes, and returns everything up to that point.
+If the delimiter is not found, the function will read until the end of the stream.
+
+```uiua
+&ru "file" &fo "example.txt"
+```
+
+In general, you only need to use streams to read from a file if the file is too large to fit in memory. For most use cases, [`&fras`]() and [`&frab`]() are sufficient.
+
+## Writing Streams
+
+The [`&w`]() (write) function writes a character or byte array to a stream. It takes the data to write and the stream handle as arguments.
+
+```uiua
+&w "Hello, world!" &fc "file.txt"
+```
+
+But wait, if we try to read from the file now, it is empty!
+
+```uiua
+&w "Hello, world!" &fc "file.txt"
+&fras "file.txt"
+```
+
+This is because the writes we have made have not been flushed to the file.
+Streams should always be closed with [`&cl`]() (close) when they are no longer needed. This will flush any remaining writes to the file and close the file handle.
+
+```uiua
+&cl &w "Hello, world!" . &fc "file.txt"
+&fras "file.txt"
+```
+
+Knowing this, we see that the examples in the section above are actually incorrect! We should close the file even after reading from it.
+
+[`under`]() can help here. It will automatically close the stream with [`&cl`]() after the block of code is executed.
+
+```uiua
+⍜(&fc "file.txt"|&w "Hello, world!")
+&fras "file.txt"
+```
\ No newline at end of file
diff --git a/docs/text/format_config.md b/docs/text/format_config.md
new file mode 100644
index 000000000..32da54a19
--- /dev/null
+++ b/docs/text/format_config.md
@@ -0,0 +1,62 @@
+
+# Uiua Formatter Configuration
+
+You can configure Uiua's formatter by creating a file called `.fmt.ua` in the directory from which you run the interpreter. This configuration file is also a Uiua program.
+
+Configuration options are specified by binding values to specific names.
+
+Example with default values:
+```uiua
+TrailingNewline ← 1
+CommentSpaceAfterHash ← 1
+MultilineIndent ← 2
+AlignComments ← 1
+IndentItemImports ← 1
+```
+The following configuration options are available:
+
+### TrailingNewline
+Type: boolean
+
+Default: `1`
+
+Whether to add a trailing newline to the output.
+
+---
+
+### CommentSpaceAfterHash
+Type: boolean
+
+Default: `1`
+
+Whether to add a space after the `#` in comments.
+
+---
+
+### MultilineIndent
+Type: natural number
+
+Default: `2`
+
+The number of spaces to indent multiline arrays and functions
+
+---
+
+### AlignComments
+Type: boolean
+
+Default: `1`
+
+Whether to align consecutive end-of-line comments
+
+---
+
+### IndentItemImports
+Type: boolean
+
+Default: `1`
+
+Whether to indent item imports
+
+---
+
diff --git a/docs/text/inverses.md b/docs/text/inverses.md
new file mode 100644
index 000000000..a7b4392fa
--- /dev/null
+++ b/docs/text/inverses.md
@@ -0,0 +1,263 @@
+# Inverses
+
+Uiua has three modifiers, [un](/docs/un), [anti](/docs/anti), and [under](/docs/under), which work with *inverses*. The inverse of a function is a function that conceptually "undoes" it.
+
+Working with inverses is a fundamental part of writing Uiua code. It is an elegant mechanism that captures many different patterns.
+
+## [un](/docs/un)
+
+The [un](/docs/un) modifier inverts the behavior of a function.
+
+```uiua
+°(+1) 5
+```
+
+```uiua
+°⊟ [1 2] # Very common!
+```
+
+```uiua
+°∿ 1 # Arcsine
+```
+
+As discussed [previously](/tutorial/arrays#array-model), [un](/docs/un)[box](/docs/box) removes an array from a box.
+
+```uiua
+°□ ⊢{"unbox" "me!"}
+```
+
+One interesting use of [un](/docs/un) is to put an array's rows onto the stack by [un](/docs/un)ing subscripted [couple](/docs/couple) or [box](/docs/box). The number of rows in the array must match though!
+
+```uiua
+⊟₃ 1 2 3
+```
+
+```uiua
+°⊟₃ [1 2 3]
+```
+
+```uiua should fail
+°⊟₄ [1 2 3]
+```
+
+[un](/docs/un)ing subscripted [box](/docs/box) will unbox the items.
+
+```uiua
+°⊟₃ {1 2_3 "hmmm"}
+```
+
+```uiua
+°□₃ {1 2_3 "hmmm"}
+```
+
+Some built-in functions that do not necessarily have a sensible or obvious inverse nevertheless have one defined anyway. The behavior is generally something that technically is *an* inverse, and which is also useful.
+
+For example [un](/docs/un) [shape](/docs/shape) generates an array of incrementing integers with the given shape.
+
+```uiua
+°△ 5_5
+```
+
+```uiua
+°△ 2_3_4
+```
+
+This is often used in examples to quickly generate a high-rank array.
+
+[un](/docs/un) [select](/docs/select) produces an array of indices for the array's rows without removing the array itself from the stack.
+```uiua
+°⊏ "enumerate"
+```
+
+You can find more uses of [un](/docs/un) in its documentation, including a list of all [un](/docs/un)-compatible functions and modifiers.
+
+## [anti](/docs/anti)
+
+The [un](/docs/un) inverse of a function must always have the opposite signature of that function. For example, if a function has signature `|2.1` (2 arguments, 1 output), then its inverse must have signature `|1.2`. This makes them easier to reason about, both for the programmer and for the compiler.
+
+This makes some things that *seem* like they have obvious inverses not actually work. For example, [un](/docs/un)[add](/docs/add) is *not* just [subtract](/docs/sub).
+
+```uiua should fail
+°+ 3 5
+```
+
+One workaround is to put one of the arguments inside the inverted function. This makes the function's signature `|1.1`, which is its own inverse.
+
+```uiua
+°(+3) 5
+```
+
+However, this is not always possible, as the argument may not be static.
+
+The [anti](/docs/anti) modifier is similar to [un](/docs/un), but it allows the use of external arguments.
+
+```uiua
+⌝+ 3 5
+```
+
+[anti](/docs/anti) is equivalent to `popunon`, and so the [anti](/docs/anti) inverse of a function with signature `|a.b` is `|(b+1).(a-1)`.
+
+[anti](/docs/anti) makes some interesting and useful behaviors available.
+
+```uiua
+⌝ⁿ 4 81 # Nth root
+```
+
+```uiua
+⌝↘ 1_¯2 [1_2 3_4] # Pad
+```
+
+```uiua
+⬚@-⌝⊏ 1_2_5 "abc"
+```
+
+```uiua
+⬚0⌝⊡ [2_2 0_4] 3_5
+```
+
+## [under](/docs/under)
+
+[under](/docs/under) expresses a more powerful inversion pattern. It captures the pattern of doing some transformation, modifying the data, then undoing the transformation.
+
+This may not seem immediately useful, but you'll find it is a pattern you encounter everywhere, even in your everyday life. You might open a drawer, take something out, then close the drawer. You might get on a bus, the bus travels, then you get off the bus.
+
+[under](/docs/under) takes two functions which we will call `F` and `G`. It calls `F`, then calls `G`, then calls an inverse of `F`.
+
+Many functions that do not work with [un](/docs/un) work with [under](/docs/under) because [under](/docs/under) can keep track of *context*. One example of this in action is [under](/docs/under)[pick](/docs/pick), which allows us to modify an element or row of an array.
+
+```uiua
+⍜(⊡2|×10) [1 2 3 4]
+```
+
+This code picks out item `2` of the array, multiplies it by `10`, then puts it back in the array.
+
+If the values passed to [under](/docs/under)'s functions are not constants, they can also be put outside, albeit in a different order.
+
+```uiua
+⍜⊡× 2 [1 2 3 4] 10
+```
+
+This works because [under](/docs/under) keeps track of the original array and passes it to the inversion of [pick](/docs/pick).
+
+If you wanted to set a value in an array rather than modifying it, you could use [pop](/docs/pop) or [gap](/docs/gap) instead of [multiply](/docs/multiply).
+
+```uiua
+⍜(⊡2)⋅∞ [1 2 3 4]
+⍜⊡◌ 2 [1 2 3 4] ∞
+```
+
+It's not just [pick](/docs/pick)! Many functions work with [under](/docs/under)!
+
+```uiua
+⍜(↙2)/× [3 5 4 2]
+```
+
+```uiua
+⍜(↻3|⊂0) [1 2 3 4 5]
+```
+
+```uiua
+⍜×⁅ 1e3 π
+```
+
+```uiua
+.↯3_4⇡12
+⍜♭⇌
+```
+
+You can even use [under](/docs/under) on a function that has already been [un](/docs/un)ed. This is a nice way to work with [box](/docs/box)ed data.
+
+```uiua
+≡⍜°□(⊂:@!) {"wow" "cool" "omg"}
+```
+
+Let's say you wanted to utilize a struct-like pattern. Uiua does not have structs or objects with fields like many other languages do, but you can simulate them with box arrays. This can be slow, so you should not do this with any data that needs to be accessed in tight loops.
+
+[under](/docs/under) allows a field getter to also be a setter!
+
+```uiua
+Person ← {⊙⊙∘}
+Name ← °□⊡0
+Surname ← °□⊡1
+Age ← °□⊡2
+
+FmtPerson ← $"_ is _ years old" ⊃(Name|Age)
+PassYear ← ⍜Age(+1)
+
+Dan ← Person "Dan" "Danson" 31
+FmtPerson Dan
+FmtPerson PassYear Dan
+```
+
+You can find more uses of [under](/docs/under) in its documentation, including a list of all [under](/docs/under)-compatible functions and modifiers.
+
+## [un](/docs/un) [by](/docs/by)
+
+The [un](/docs/un) [by](/docs/by) pattern allows you to access the "undo" part of a function's [under](/docs/under) inverse without the "do" part. This only works for monadic functions.
+
+For example, [under](/docs/under) [first](/docs/first) allows you to modify the first row of an array. Therefore, [un](/docs/un) [by](/docs/by) [first](/docs/first) allows you to *set* the first row of an array.
+
+```uiua
+⍜⊢(×10) [2 3 4]
+```
+
+```uiua
+°⊸⊢ 0 [2 3 4]
+```
+
+This is useful to set rows that are at static indices.
+
+```uiua
+°⊸(⊡2) 5 [1 2 3 4]
+```
+
+## Setting Inverses with [obverse](/docs/obverse)
+
+There are many functions, especially more complex ones, for which the compiler cannot automatically infer an inverse. To maximize the power of a function, you may wish to define various inverses for it.
+
+The [obverse](/docs/obverse) modifier offers a flexible system for defining multiple inverses for a function.
+
+You can read [obverse](/docs/obverse)'s docs for the full details on how to use it, but we'll show a simple example here.
+
+Let's say you want to define a linear interpolation function `Lerp`. The first argument will be a two-element list that is a range to interpolate between. The second argument will be a parameter to interpolate with. A parameter of `0` gives the lower value of the range. A parameter of `1` gives the higher value. All other parameter values are allowed.
+
+```uiua
+Lerp ← +⊃⊢(×/-)
+Lerp 10_20 0
+Lerp 10_20 0.5
+Lerp 10_20 1
+Lerp 10_20 1.5
+Lerp 10_20 2
+```
+
+Unfortunately, the way `Lerp` has been implemented here is not invertible by the compiler.
+
+```uiua should fail
+Lerp ← +⊃⊢(×/-)
+°(Lerp 10_20) 30
+```
+
+To define an inverse, we can provide a function pack of two functions to [obverse](/docs/obverse). The first function is the normal code to run, our existing `Lerp` code. The second function is our provided inverse.
+
+In this case, the inverse function takes a range and an output value and determines the corresponding parameter.
+
+```uiua
+Lerp ← ⌅(
+ +⊃⊢(×/-) # Normal lerp
+| ÷⊃/-(-⊢) # Invert the lerp
+)
+```
+
+This inverse ends up working with [un](/docs/un), [anti](/docs/anti), *and* [under](/docs/under)!
+
+```uiua
+Lerp ← ⌅(+⊃⊢(×/-)|÷⊃/-(-⊢))
+Lerp 10_20 0.5
+°(Lerp 10_20) 30
+⌝Lerp 10_20 5
+⍜Lerp(+5) 10_20 0.5
+```
+
+Sometimes more nuanced inverses are required. Maybe the behavior for the [un](/docs/un), [anti](/docs/anti), and [under](/docs/under) inverses needs to be subtly different in some way. Fully specifying all inverses simply requires providing [obverse](/docs/obverse) a function pack with more functions. The full description of how this works is in its documentation.
+
+Defining custom inverses for functions allows you to create powerful and flexible behaviors, often encapsulating multiple functionalities into a single function. They are useful for everything from reversible mathematical transformations to all-in-one encoding/decoding functions.
\ No newline at end of file
diff --git a/docs/text/macros.md b/docs/text/macros.md
new file mode 100644
index 000000000..48410538e
--- /dev/null
+++ b/docs/text/macros.md
@@ -0,0 +1,158 @@
+# Macros
+Defining your own functions that work on arrays is pretty easy. Just a name, a `←`, and you're done.
+
+But what if you want to define functions that use other functions?
+
+## Placeholders and `!`s
+Anywhere you can put a built-in or inline function, you can also put a `^` followed by a number. This is called a *placeholder*.
+
+Any named function with `^`s in it is a macro.
+
+However, there is one additional requirement: macros must have names that end in as many `!`s as the number of functions they take.
+
+Macros work similarly to modifiers. They take some function arguments and modify how they are used.
+
+The number that comes after a `^` is the index of the function argument passed to the macro.
+
+Let's look at a simple example using [reduce](). It reduces a function over the numbers up to the given range.
+
+```uiua
+ReduceRange! ← /^0+1⇡
+ReduceRange!+5
+ReduceRange!×4
+```
+
+Here is another simple example which calls a function on a reversed version of each row of an array.
+
+```uiua
+OnRev! ← ≡⍜⇌^0
+OnRev!(↘1) ↯3_4⇡12
+OnRev!(⊂π) ↯3_4⇡12
+```
+
+A macro can take as many functions as you want. Modifiers with two or more function arguments will be formatted to use `‼`s as needed. Try running the following example to format it.
+
+```uiua
+F!!! ← ⊂/^0⊃^1^2
+F!!!+×⊂ [1 2 3][4 5 6]
+```
+
+Placeholders with the same number can of course be reused to use that function multiple times.
+
+For example, if we wanted to call each of two functions twice, but in a different order:
+
+```uiua
+F‼ ← ^1^0^0^1
+F‼(×2|+1) 5
+F‼(+1|⊂0) 1
+```
+
+## Two Kinds of Macros
+The macros described so far are called *index macros*, because arguments are referenced directly by their position when the macro is called.
+
+But Uiua actually has a second kind of macro. *Code macros* put their operands in an array. The array can then be arbitrarily manipulated with normal Uiua code.
+
+## Code Macros
+Code macros are defined by putting a `^` right after the binding's `←`. Code macro names must still end in some number of `!`s.
+
+Here is a basic example that simply prints its operands. It returns the number `5` as the actual generated code.
+
+```uiua
+F‼ ←^ "5" &pf
+F‼⊂(+1)
+```
+
+As you can see, the operands are passed to the function as an array of boxed strings.
+
+Code macros may be passed a function pack operand. Each operand from the pack will be put in the array.
+
+```uiua
+F! ←^ $"_"
+F!(+|-|×|÷)
+```
+
+The code macro's function must return either a string or an array of boxed strings. This value will be converted back to Uiua code and compiled as normal.
+
+Format strings can help a lot in generating new code. For example, if we wanted to make a version of [both]() that calls its function on an arbitrary number of sets of values, we could use [reshape]() and [bracket]().
+
+```uiua
+All‼ ←^ $"⊓(_)" /$"_|_" ↯⋕ °{⊙∘}
+[All‼3+ 1 2 3 4 5 6]
+```
+
+First, we extract the two operands: the count and the function. The count comes in as a string, so we have to [parse]() it before using [reshape]() to make an array of copies of the function.
+
+We use [reduce]() with a format string to form the branches of a function pack, then use another format string to put them in [bracket]().
+
+The resulting string is then compiled as Uiua code.
+
+Code macros have the ability to create new bindings, including new macros.
+
+```uiua
+Def‼ ←^ $"_\n_" ⊃(/$"_ ← _"|/$"Also_ ← _")
+Def‼(X|5)
++ X AlsoX
+```
+
+This is a simple example, but this concept can be used to create very powerful meta-programming tools.
+
+If a code macro's function takes 2 arguments, the second argument will be an array of the signatures of the functions passed to the macro.
+
+```uiua
+Sigs! ←^ ⍚$"\"_ is |_._\"" ⊙≡°⊟
+Sigs!(+|∿|⊓+¯)
+```
+
+Non-string values returned from a code macro will be implicitly converted to strings via [repr]().
+
+```uiua
+SigOf! ←^ ⋅⊢ # Gets the signature
+SigOf!+
+SigOf!⊓+¯
+```
+
+## Compile Time vs Run Time
+The body of a code macro is always evaluated at compile time. One consequence of this is that bindings whose values cannot be known at compile time cannot be used in a code macro.
+
+For example, because the value `5` is always the same, it is always known at compile time, and we can use a name that binds `5` in a code macro.
+
+```uiua
+x ← 5
+F! ←^ $"_ _":x ⊢
+F!¯
+```
+
+However, if we use a value that cannot be known at compile time, like the result of the [rand]() function, we will get an error.
+
+```uiua should fail
+x ← ⚂
+F! ←^ $"_ _":x ⊢
+F!¯
+```
+
+There are two ways to work around this. The first is to simply put the code that generates the value in the macro itself.
+
+```uiua
+F! ←^ $"_ ⚂" ⊢
+F!¯
+```
+
+The second is to use the [comptime]() modifier, which forces its function to be evaluated at compile time.
+
+```uiua
+x ← comptime(⚂)
+F! ←^ $"_ _":x ⊢
+F!¯
+```
+
+## What kind of macro should I use?
+Which kind of macro you use depends on what kind of code you are writing.
+
+Code macros are much more powerful than index macros, but they can be more complicated to write.
+
+Additionally, index macros are [hygienic](https://en.wikipedia.org/wiki/hygienic_macro). When an index macro refers to names of things, bindings you have defined in the surrounding code will not interfere; you will never accidentally use the wrong binding. Code macros make no such guarantees.
+
+If you conceptually just want to define your own modifier, an index macro is probably the simplest way to go.
+
+If you want the full power (and all the complexity) of compile-time meta-programming, you'll need to use a code macro.
+
diff --git a/docs/text/ranges.md b/docs/text/ranges.md
new file mode 100644
index 000000000..6cbe25cfc
--- /dev/null
+++ b/docs/text/ranges.md
@@ -0,0 +1,107 @@
+# Ranges
+
+Working with regular sequences of numbers is a common task in programming. Many languages handle this with with a `for` loop, but Uiua uses the same construct it uses for most things: arrays.
+
+## [`range`]()
+
+[`range`]() is the fundamental range-generating function. It generates an array that is the range of integers `[0, n)`.
+
+```uiua
+⇡5
+⇡12
+```
+
+If you want to include the end value to get the range `[0, n]`, you can [`add`]()`1` first.
+
+```uiua
+⇡+1 5
+⇡+1 12
+```
+
+[`add`]()`1` afterward to get the range `[1, n]`.
+
+```uiua
++1⇡ 5
++1⇡ 12
+```
+
+The [`range`]() of a negative number gives the range `(0, n]`.
+```uiua
+⇡¯5
+⇡¯12
+```
+
+## [`under`]() Tricks
+
+[`under`]() makes getting more complex ranges simple.
+
+For example, here is a simple way to get the range `[a, b)`:
+
+```uiua
+⍜-⇡ 3 10
+```
+The order of operations here is:
+- Subtract `3` from `10` to get `7`
+- Generate the range `[0, 7)`
+- Add `3` back to that range to get `[3, 10)`
+
+The definition of [`range`]() on negative numbers means that this idiom also works in reverse.
+
+```uiua
+⍜-⇡ 10 3
+```
+
+You can replace [`subtract`]() with [`divide`]() to use a step size.
+
+```uiua
+⍜÷⇡ 0.5 4
+```
+
+This only works if the numbers are divisible. If they are not, you need to use [`floor`](), [`ceiling`](), or [`round`]().
+
+```uiua
+⍜÷(⇡⌊) 3 10
+⍜÷(⇡⌈) 3 10
+⍜÷(⇡⁅) 3 10
+```
+
+These techniques can be combined to get more complex ranges:
+
+```uiua
+⍜(÷⊙-|⇡⌈) 3 10 20
+```
+
+## [`un`]() Ranges
+
+It is often necessary to generate a range that has as many elements as an array has rows.
+
+The intuitive way to do this is with [`length`]().
+
+```uiua
+⇡⧻. "Hello!"
+```
+
+This is a very common operation. [`un`]() [`select`]() is defined as a shortcut for this.
+[`select`]() takes a list of indices, so [`un`]() [`select`]() *returns* a list of indices.
+
+```uiua
+°⊏ "Hello!"
+```
+
+This same pattern is used for the [`un`]()-inverses of [`pick`]() and [`orient`]().
+
+```uiua
+A ← ["Hello" "World"]
+≍ ⊃(⇡⧻|⊙◌°⊏) A # Range of length
+≍ ⊃(⇡△|⊙◌°⊡) A # Range of shape
+≍ ⊃(⇡⧻△|⊙◌°⤸) A # Range of rank
+```
+
+It is simple to verify that these inverses are correct.
+
+```uiua
+A ← ["Hello" "World"]
+⊏°⊏ A
+⊡°⊡ A
+⤸°⤸ A
+```
diff --git a/docs/text/strings.md b/docs/text/strings.md
new file mode 100644
index 000000000..9501c64f9
--- /dev/null
+++ b/docs/text/strings.md
@@ -0,0 +1,136 @@
+# Working with Strings
+
+There is a common misconception that array languages like Uiua are only really good for mathematical tasks; that rich text processing is better left to more traditional languages. This is not the case! Strings are, after all, just arrays of characters!
+
+That being said, it may not be immediately clear how to perform common string manipulations in Uiua. This tutorial will cover the basics.
+
+## Converting numbers with [`parse`]()
+
+[`parse`]() is the standard way to convert a string to a number.
+```uiua
+⋕"5.2"
+```
+It can also be used on arrays of boxed strings.
+```uiua
+⋕{"3" "-16" "π" "1e3"}
+```
+[`un`]()[`parse`]() will convert numbers to strings.
+```uiua
+°⋕ 10
+°⋕ [1 2 3]
+°⋕ ↯3_4⇡12
+```
+
+## Splitting with [`partition`]()
+
+As discussed in the [Thinking With Arrays](/tutorial/thinkingwitharrays) tutorial, [`partition`]() can be used to split an array by a delimiter.
+
+First, we create a mask of places where the delimiter is *not* using [`by`]() [`not equals ≠`](). In this case, we'll use the space character.
+```uiua
+⊸≠@ "Split this string"
+```
+[`partition`]() will then split the strings at the places where the mask changes, omitting `0`s.
+```uiua
+⊜□ ⊸≠@ "Split this string"
+```
+Notice that this reads almost as a description of what it does: "Partition box by not equals space"
+
+This can be nested to split by multiple delimiters.
+```uiua
+"A string\nwith multiple\nlines"
+⊜(□⊜□⊸≠@ )⊸≠@\n
+```
+
+For parts of the string that are not the first or last, we can simply [`box`]() and [`select`]().
+```uiua
+⊏1_3 ⊜□⊸≠@, "lorem,ipsum,dolor,sit,amet"
+```
+
+[`partition`]() can be nested to split by multiple delimiters.
+
+For example, if you were reading from a file that contained rows of numbers separated by spaces, you could use [`partition`]() to create a multi-dimensional array.
+
+Here, the contents of the file will be represented as a multi-line string. We use [`parse`]() as the inner function to parse the numbers.
+
+```uiua
+$ 1 8 4 99
+$ 5 20 0 0
+$ 78 101 1 8
+⊜(⊜⋕⊸≠@ )⊸≠@\n
+```
+
+This assumes that the two delimiters delimit different dimensions of the array. If they delimit the same dimension, we can use [`not`]() and [`memberof`]().
+```uiua
+$ 1 8 4 99
+$ 5 20 0 0
+$ 78 101 1 8
+⊜⋕¬⊸∈" \n"
+```
+
+## Finding substrings with [`mask`]()
+
+What if we want to split by a non-scalar delimiter? Simply dropping a string delimiter into the code above produces an error.
+```uiua should fail
+⊜□ ⊸≠" - " "foo - bar - ba-az"
+```
+We might try [`find`](). While there may be cases when this output is useful, it is not quite what we want here.
+```uiua
+ ⊸⌕" - " "foo - bar - ba-az"
+⊜□ ¬⊸⌕" - " "foo - bar - ba-az"
+```
+This is because [`find`]() only marks the start of each matching substring.
+
+[`mask`]() marks each substring with an increasing number.
+```uiua
+⊸⦷" - " "foo - bar - ba-az"
+```
+This works great with [`partition`]() to split the string how we want.
+```uiua
+ ⊸⦷" - " "foo - bar - ba-az"
+ ¬⊸⦷" - " "foo - bar - ba-az"
+⊜□ ¬⊸⦷" - " "foo - bar - ba-az"
+```
+Notice that while [`not`]() leaves parts of the mask negative, [`partition`]() ignores all sections that are not positive.
+
+## Replacing substrings with [`under`]()
+
+Because [`under`]() works with [`partition`](), we can use it with [`mask`]() to replace substrings.
+
+In this example, we replace each row of the [`partition`]()ed array with the string `"orb"`.
+```uiua
+ ⊸⦷ "ab" "abracadabra"
+ ⊜∘ ⊸⦷ "ab" "abracadabra"
+⍜⊜∘≡⋅"orb" ⊸⦷ "ab" "abracadabra"
+```
+This can even be used to replace the matches with different strings.
+```uiua
+⍜⊜□◌ ⊸⦷ "ab" "abracadabra" {"[first]" "[second]"}
+```
+Here is how you might replace with a variable number of strings.
+```uiua
+F ← ⍜⊜□(↙⧻) ⊸⦷ "ab" :°⋕⇡10
+F "abracadabra"
+F "abcdefg"
+F "ababab|abababab"
+```
+
+## [`regex`]()
+
+When a string search operation is especially complicated, you can always fall back to regular expressions using [`regex`]().
+
+Uiua uses [Rust's regex engine](https://docs.rs/regex) under the hood, so you can use the same syntax as you would in Rust.
+
+[`regex`]() returns a table of boxed strings. The first element in each row is the match. Subsequent elements are the captures.
+```uiua
+regex "\\d{3,4}" "(555) 310-1984"
+```
+```uiua
+regex "a([bc])" "abracadabra"
+```
+Optional captures may need [`fill`]() to avoid errors.
+```uiua should fail
+regex "foo(bar)?(baz)?" "foobar\nfoobaz"
+```
+```uiua
+⬚""regex "foo(bar)?(baz)?" "foobar\nfoobaz"
+```
\ No newline at end of file
diff --git a/docs/text/tacit_code.md b/docs/text/tacit_code.md
new file mode 100644
index 000000000..5b46857ea
--- /dev/null
+++ b/docs/text/tacit_code.md
@@ -0,0 +1,236 @@
+# Tacit Code
+
+So far, most of the code examples in this tutorial have been fairly short. While Uiua is great for short, simple code, it is designed to be a general-purpose language. Uiua aims to be decent for everything from Code Golf to command-line utilities, from websites to games.
+
+However, it may not be immediately clear how to write more complex code that does not refer to variable names.
+
+## What Uiua asks of you
+
+When you first start using Uiua beyond just simple examples and challenges, you will likely encounter difficulty passing more than a couple values around.
+
+In disallowing named local variables, Uiua asks something of the programmer that most other languages do not. It asks that you re-orient the way you think about data. How you refer to it, how it flows through a program.
+
+If you pay the price of this re-orientation, Uiua offers you a few things in return.
+
+For one, you end up writing a lot less code. When you don't bind lots of local variables and constantly refer to them in expressions, your code ends up being much shorter. This makes scanning through code require less scrolling and jumping around.
+
+This is one of the many ways that Uiua reduces *ceremony.* Ceremony in a programming language is all the code you have to write that is not directly related to the problem you are trying to solve. This includes everything from minor syntax like braces and keywords to complex boilerplate like interface implementations. Uiua does not eliminate all ceremony (no language can), but it aims to eliminate as much as possible while maintaining a certain level of readability and structure.
+
+This is not to say that local bindings are not useful in other languages. There are two original motivations for Uiua eliminating local variables: simplicity of implementation, and beauty.
+
+*If you are not too concerned with performance and implementation, you can skip this paragraph.* Uiua's arrays are garbage-collected via reference counting. This reference count is also used when mutating an array. For example, if you [reverse]() an array when no duplicates exist, the array is simply reversed in place. However, if at least one other copy of the array exists on the stack, the array's entire buffer will be copied, and this new copy will be reversed instead. If variables could be locally bound, a copy would have to be stored for the duration of the variable's scope. Without complex escape analysis, this could lead to unnecessary copies when using local variables. Because values on the stack are cleaned up as they are used, arrays only need to be copied as often as is actually necessary!
+
+But in the end, the primary motivation for forbidding local variables is that leads to code that is both beautiful and enjoyable to write. This is, of course, highly subjective, but if you've made it this far into the tutorial, then hopefully you've seen some of that beauty, felt some of that joy.
+
+## The Stack Pitfall
+
+Being stack-based is Uiua's key to being usable as a pure-tacit language. However, the stack can be an unwieldy tool if used recklessly. Many stack languages have built-in functions for rotating the stack, fishing values up from deep in the stack, or arbitrarily reordering it. While these things are technically possible in Uiua, they are discouraged, and the code for them is verbose by design.
+
+Uiua encourages a more structured approach to stack manipulation. There are no single functions for rotating the stack or for swapping more than 2 values.
+
+When complex stack manipulation *is* required, it is usually done with [planet notation](/tutorial/advancedstack#planet-notation). Planet notation allows you to *visualize* the way values move around.
+
+## A Motivating Example
+
+The online Uiua pad and the `uiua watch` command in the native interpreter make it easy to write Uiua code interactively. You can easily see the state of the stack after each change you make to the code.
+
+This iterative process is good for exploring possibilities, and it is the intended way to write Uiua code. However, a naive, ad-hoc approach to stack manipulation often leads to code that is very hard to read.
+
+As a motivating example, let's attempt to implement the quadratic formula. Given numbers `a`, `b`, and `c`, the roots of the function `ax² + bx + c` can be found via the expression `(-b ± √(b² - 4ac)) / 2a`.
+
+This is a useful example because it involves juggling 3 arguments that are used in a non-regular way.
+
+Let's start with the discriminant term ` b² - 4ac`.
+
+```uiua
+Disc ← # Code goes here
+Disc 1 ¯3 2
+```
+
+To show how you might build up a solution with only stack reordering, we'll only use [`duplicate`](), [`flip`](), [`over`](), and [`dip`]() to attempt to get all the arguments in the right order.
+
+First, we'll might try to get `a` and `c` next to each other above `b` on the stack.
+
+```uiua
+Disc ← ⊙:
+Disc 1 ¯3 2
+```
+
+Because `a` and `c` are on top of the stack, making the `4ac` term is easy.
+
+```uiua
+Disc ← ××4 ⊙:
+Disc 1 ¯3 2
+```
+
+We can get down to `b` with [dip](), create the `b²` term, and [subtract]().
+
+```uiua
+Disc ← -⊙(ⁿ2)××4 ⊙:
+Disc 1 ¯3 2
+```
+
+That finishes the discriminant. Next, we'll account for [complex]() roots and take the [sqrt]().
+
+```uiua
+Disc ← √ℂ0 -⊙(ⁿ2)××4 ⊙:
+Disc 1 ¯3 2
+```
+
+We can implement `±` by [couple]()ing the value with itself [negate]()d.
+
+```uiua
+Quad ← ⊟¯. √ℂ0 -⊙(ⁿ2)××4 ⊙:
+Quad 1 ¯3 2
+```
+
+And now we have a problem. We still need to use `a` and `b` one more time, but they have already been consumed.
+`a` and `b` start at the top of the stack, so we can copy them with [over]() and put the rest of out code in two [dip]()s.
+
+```uiua
+Quad ← ⊙⊙(⊟¯. √ℂ0 -⊙(ⁿ2)××4 ⊙:),,
+Quad 1 ¯3 2
+```
+
+Then we'll [subtract]() `b`...
+
+```uiua
+Quad ← ⊙(-⊙(⊟¯. √ℂ0 -⊙(ⁿ2)××4 ⊙:)),,
+Quad 1 ¯3 2
+```
+
+...and [divide]() by `2a`.
+
+```uiua
+Quad ← ÷×2⊙(-⊙(⊟¯. √ℂ0 -⊙(ⁿ2)××4 ⊙:)),,
+Quad 1 ¯3 2
+```
+
+And there we have it, the quadratic formula.
+
+```uiua
+Quad ← ÷×2⊙(-⊙(⊟¯. √ℂ0 -⊙(ⁿ2)××4 ⊙:)),,
+Quad 1 ¯3 2
+Quad 1 2 5
+Quad 2 3 1
+```
+
+On close inspection, the astute reader may notice that the above code sucks. What's worse, it's not even as bad as it could be. If you hadn't thought to use [over]() and [dip]() in that way, you may have instead used `:⊙:` to rotate 3 values on the stack, making it even more convoluted.
+
+The problem with reordering stack values this often is that the state of the stack at any point in the code gets harder and harder for the writer to keep in their head. It also makes it much harder for the reader to deduce the state of the stack at a glance.
+
+## Stack-Source Locality
+
+The code above is also obtuse for another reason.
+
+Imagine a person who is less familiar with this code going to read it. It may be someone else, but it may also be a future version of yourself. If they look at the leftmost term `÷×2`, they'll likely be able to quickly tell that it takes two arguments. But how do they figure out what those arguments are? They would have to make their way all the way to the *other side of the function* to find the [over]() that creates the copy of `a`. They would only end up there after having built up the mental model of the state of the stack throughout the *entire function*.
+
+This obtuseness is the result of the above code violating a fundamental principle of writing good Uiua code, that of *stack-source locality*. Stated simply, **code that creates values should be as close as possible to the code that uses those values**.
+
+In our example, [divide]() and the [over]() that creates its argument are on opposite sides of the function: a massive violation of stack-source locality.
+
+This principle is not a formula you can plug values into. It is not a set of procedures that will make code better. It is a guiding tenet meant to shape the way you think about the flow of your data and how you structure your programs. How well a given code snippet maintains stack-source locality is up to interpretation, and different Uiua programmers may interpret it differently, even for the same program.
+
+## A Better Way
+
+So how do we write better Uiua code? How do we keep stack-source locality? How do we avoid making the stack so convoluted that our code becomes unreadable?
+
+The short answer is to make liberal use of [fork]().
+
+The power of [fork](), [dip](), [gap](), [on](), and [by]() is that they allow access to arbitrary values on the stack *without* reordering it. When the stack maintains its order, it is much easier to reason about values' position on it, since their positions seldom change relative to each other.
+
+Let's redo the quadratic formula implementation using these modifiers.
+
+We'll start again with the discriminant.
+
+```uiua
+Disc ← -⊃(××4⊙⋅∘)⋅(ⁿ2)
+Disc 1 ¯3 2
+```
+
+Notice that when we use planet notation, it is easier to tell which functions are being applied to which values.
+
+We'll implement the `√` and `±` in the same way as before.
+
+```uiua
+Disc ← ⊟¯. √ℂ0 -⊃(××4⊙⋅∘)⋅(ⁿ2)
+Disc 1 ¯3 2
+```
+
+Even though `b` has been consumed, we can gain access to it again using another [fork]() and implement the `-b` term.
+
+```uiua
+Quad ← -⊃⋅∘(⊟¯. √ℂ0 -⊃(××4⊙⋅∘)⋅(ⁿ2))
+Quad 1 ¯3 2
+```
+
+Then, we can use another [fork]() to add the `/ 2a` part.
+
+```uiua
+Quad ← ÷⊃(×2|-⊃⋅∘(⊟¯. √ℂ0 -⊃(××4⊙⋅∘)⋅(ⁿ2)))
+Quad 1 ¯3 2
+```
+
+Long lines like this can hurt readability. One thing we can do to alleviate this is split the discriminant onto its own line.
+
+```uiua
+Quad ← ÷⊃(×2)(
+ -⊃⋅∘(
+ -⊃(××4⊙⋅∘)⋅(ⁿ2)
+ ⊟¯. √ℂ0
+ )
+)
+Quad 1 ¯3 2
+```
+
+Alternatively, we can pull the discriminant into its own function.
+
+```uiua
+# A thing of beauty
+Disc ← -⊃(××4⊙⋅∘)⋅(ⁿ2)
+Quad ← ÷⊃(×2|-⊃⋅∘(⊟¯. √ℂ0 Disc))
+Quad 1 ¯3 2
+```
+
+Let's compare this solution to the previous one. To improve the comparison, we'll make the discriminant its own function here as well.
+
+```uiua
+Disc ← -⊙(ⁿ2)××4 ⊙:
+Quad ← ÷×2⊙(-⊙(⊟¯. √ℂ0 Disc)),,
+Quad 1 ¯3 2
+```
+
+The difference is night-and-day. The old, naive solution, even with the benefit of being broken up, still has all of its same issues.
+
+If we look in the improved solution and do the same search for the source of [divide]()'s arguments, we don't have to go far before finding the [fork]() with `×2` and `-`. Stack-source locality holds for all parts of the code!
+
+# When to Reorder
+
+While reordering stack values is discouraged, a little bit of reordering up front can sometimes greatly simplify subsequent code. The recommended place to do this is at the very beginning of a function.
+
+A function should *take* its arguments in the order that is most natural for calling. If necessary, you may choose to reorder a functions arguments at the beginning of its body so that they are easier to work with inside the function.
+
+If we for some reason decided that the best calling order for our `Quad` function was `c` `b` `a`, then we could add a reordering step to the beginning and keep the rest of the implementation the same.
+
+```uiua
+Disc ← -⊃(××4⊙⋅∘)⋅(ⁿ2)
+Quad ← (
+ ⊃(⋅⋅∘|⋅∘|∘) # Reorder
+ ÷⊃(×2|-⊃⋅∘(⊟¯. √ℂ0 Disc))
+)
+Quad 0 2 1
+```
+
+Even though the reordering step could be written shorter as `⊃⋅⋅∘:` it is written in a long form here for the benefit of the reader. But you may decide that `⊃⋅⋅∘:` is perfectly clear, and that's fine!
+
+## Three Rules
+
+As stated before, the advice in this section is just that, advice. It is not a set of hard and fast rules that must be followed.
+
+However, if you are the kind of person that *likes* a simple list of rules, then here it is:
+
+- **Reorder the stack as little as possible**
+- **Break up long lines with whitespace or into separate functions**
+- **Maintain stack-source locality**
+
+Like all programming languages (though perhaps more than some), writing Uiua code is as much art as it is science. The deconstruction of a problem, the synthesis of a solution, the care for the reader; these are all things you get a feel for as you work more with the language.
\ No newline at end of file
diff --git a/docs/text/testing.md b/docs/text/testing.md
new file mode 100644
index 000000000..8dba0c05f
--- /dev/null
+++ b/docs/text/testing.md
@@ -0,0 +1,81 @@
+# Testing
+
+Testing is important for ensuring that code works as expected, especially in a dynamic language like Uiua.
+
+The language has a couple built-in mechanisms for streamlining testing.
+
+## [assert](/docs/assert) Tests
+
+The [assert](/docs/assert) function will return an error when its second argument is anything other than `1`.
+
+While this can be used in some forms of [control flow](/tutorial/controlflow), it is also useful for testing.
+
+When testing is enabled (as it is in all editors on this website), a line with [assert](/docs/assert) at the beginning will be interpreted as a test.
+
+```uiua should fail
+Square ← ×.
+⍤. =9 Square 3
+⍤. =12 Square 4
+⍤. =225 Square 15
+```
+
+As you can see, these when one of these top-level [assert](/docs/assert)s fails, the program continues running.
+When the program is done running, the successes and failures are aggregated and displayed.
+
+## Test Scopes
+
+A [scoped module](/tutorial/modules#scoped-modules) with the name `test` is special in that code inside it will *not* be run when using the `uiua run` command. The `uiua test` and `uiua watch` commands *will* run test scope code. Test scopes are also always run on this website.
+
+```uiua
+Square ← ×.
+┌─╴test
+ ⍤. =9 Square 3
+ ⍤. =225 Square 15
+└─╴
+```
+
+Importantly, `uiua run` will not run test scopes, but it will *also* not interpret any [assert](/docs/assert)s as tests.
+
+## Testing Patterns
+
+The first argument to [assert](/docs/assert) is the value that will be thrown if the assertion fails. In the examples above, we have simply been [duplicate](/docs/duplicate)ing the test value. We can throw a message instead.
+
+If the result does not match the expectation, that incorrect result will be thrown.
+
+```uiua should fail
+Square ← ×.
+⍤"3² is not 9!" =9 Square 3
+⍤"4² is not 12!" =12 Square 4
+⍤"15² is not 225!" =225 Square 15
+```
+
+One nice pattern for writing tests is to put the expected result before the test computation and use `assert``with``match`. This has the nice mnemonic spelling "assert with match".
+
+This should be immediately followed by the expected result.
+
+```uiua should fail
+Square ← ×.
+⍤⤙≍ 9 Square 3
+⍤⤙≍ 12 Square 4
+⍤⤙≍ 225 Square 15
+⍤⤙≍ [1 2 3] ⊂ 1 [2 3]
+```
+
+Notice how the expected value appears in the error message.
+
+```uiua
+F ← ⍣⍜⊢(+1)∘
+┌─╴test
+ ⍤⤙≍ [2 2 3] F [1 2 3]
+ ⍤⤙≍ [4 5 7] F [3 5 7]
+ ⍤⤙≍ "viua" F "uiua"
+ ⍤⤙≍ [] F []
+└─╴
+```
+
+If a function returns multiple values, you can simply box them with `{}`s.
+
+```uiua
+⍤⤙≍ {1 2_3} {°⊂} [1 2 3]
+⍤⤙≍ {1_2 3_4_5} {⊃↙↘2} [1 2 3 4 5]
+```
\ No newline at end of file
diff --git a/docs/text/tour.md b/docs/text/tour.md
new file mode 100644
index 000000000..1626e29cc
--- /dev/null
+++ b/docs/text/tour.md
@@ -0,0 +1,467 @@
+# Uiua Language Tour
+
+## The Union of Two Paradigms
+
+Uiua is a programming language that incorporates two of the less-common programming paradigms: **array-oriented** and **stack-based**.
+
+An **array-oriented** language is one where the primary data structure is the array. In array languages, many operations that can apply to a single value can also apply to every value in an array. This is known as *rank-polymorphism*.
+
+A **stack-based** language is one where all operations manipulate a global stack of values. Functions pop values off the top of the stack, perform their calculation, then push the results back onto the stack.
+
+In Uiua, functions work on a global stack of arrays.
+
+That's enough introduction, let's see some code!
+
+```uiua
++1 ×2 ⇡10
+```
+
+Uiua code runs from [right to left](../rtl), top to bottom. Operators are put to the *left* of their arguments, rather than in-between.
+
+This program makes an array of all the numbers less than 10, multiplies each one by 2, then adds 1 to each.
+
+If you want to see how that works step-by-step, try clicking the arrows beside the Run button.
+
+Now, I can already hear you asking, *"Wait, what is that funny arrow? How am I supposed to type the multiplication sign?"*
+
+Unlike some other array languages, Uiua does not require a special keyboard configuration or an editor with custom keybindings. Instead, you can type either the ASCII symbol or the name of a built-in function, then the Uiua formatter will convert it to the correct Unicode glyph.
+
+In this case, the ASCII symbol for multiplication is `*` and the name of the funny arrow is [range](/docs/range).
+
+On this website, you can format by clicking **Run** or by pressing **Ctrl+Enter** with the cursor in the text area. Try it out!
+
+```uiua
++1*2 range10
+```
+
+You don't even have to type the whole name of a built-in function, just enough to disambiguate it from the others.
+
+```uiua
+ran10
+```
+
+If you're ever not sure what a glyph is called, you can hold ctrl/⌘ and hover over it to see its name.
+
+You can ctrl/⌘-click any glyph in the editor to see its documentation.
+
+Click the `↧` on the right of the editor to see a list of all the built-in functions.
+
+## The Stack
+
+A number in Uiua code pushes its value to the stack. On the website's editor, the values on *top* of the stack are displayed at the *bottom*. This is so that sequential lines of code show their result in the correct order.
+
+```uiua
+10 11
+@c
++1 2
+"Hello, World!"
+# By the way, comments start with #
+```
+
+If you like, you can put values on the stack first, then operate on them.
+
+```uiua
+×++ 1 2 3 4
+```
+
+[Dup](/docs/dup) duplicates the top value on the stack.
+
+```uiua
+×.3
+```
+
+[Dup](/docs/dup) is often used in the examples on this site to show both the input and output of a function.
+
+```uiua
+√.225
+```
+
+For math functions where the order matters, like [sub](/docs/sub) and [div](/docs/div), what would normally be the second argument is instead the first. This is so you can think of fragments like `¯2` as a single unit.
+
+If you want them to work the other way, you can use [flip](/docs/flip), which swaps the top two values on the stack.
+
+```uiua
+-3 10
+-:3 10
+```
+
+By the way, since `-` is for [subtract](/docs/subtract), use `` ` `` for negative numbers. The formatter will turn it into a nice `¯`.
+
+```uiua
+`10
+```
+
+You can inspect the stack at any point with [stack](/docs/stack).
+
+```uiua
++1?×2?×.-3 5
+```
+
+## Arrays
+
+So far, we have only talked about the stack part of Uiua. Now, let's talk about the most important part: Arrays!
+
+An array is a rectangular collection of elements arranged along some number of axes.
+
+An array with no axes is called a scalar. All the numbers in the examples above are scalars.
+
+An array with one axis is often called a list or a vector. An array with two axes is often called a table or a matrix.
+
+You can make simple lists by putting `_`s between the elements.
+
+```uiua
+1_2_3_4
+```
+
+You can also just surround them with `[]`s.
+
+```uiua
+[5 6 7 8]
+```
+
+But wait! You can put whatever code you want between the brackets! The code runs from right to left as normal, and any values pushed to the stack get put in the array!
+
+```uiua
+[×3 . -2 . 10]
+```
+
+If you put arrays inside others, you can make arrays with multiple dimensions.
+
+```uiua
+[1_2_3 [4 5 6] 7_8_9]
+```
+
+```uiua
+[×3. 4_5_6]
+```
+
+Some operations are *pervasive*, which means they apply to every element of an array or every pair of elements between two arrays. All the math operators are pervasive!
+
+```uiua
+√[4 9 16]
+```
+
+```uiua
+×2 [1 2 3]
+```
+
+```uiua
++ 1_2_3 4_5_6
+```
+
+```uiua
+× 2_10 [1_2_3 4_5_6]
+```
+
+Arrays have a [shape](/docs/shape) that describes how many elements they have along each axis.
+
+```uiua
+△5
+△[]
+△[9 1 6]
+△[4_π_9 1_5_∞]
+```
+
+The *rank* of an array refers to the number of axes it has.
+
+The [len](/docs/len) is the number of rows it has along its first axis.
+
+```uiua
+a ← [1_2_3_4 5_6_7_8 9_10_11_12]
+△a
+⧻a
+⧻△a # rank
+```
+
+If you want to type that fancy `←` so you can give names to arrays, you can type `=` after a name at the start of a line, and the formatter will convert it for you.
+
+```uiua
+x = 5
++x x
+```
+
+`←` just pops the first thing off the stack and assigns it to the name on the left, so if there is already a value on the stack, you don't actually need anything on the right.
+
+```uiua
+×2 [2 3 4]
+x ←
+x
+```
+
+Names are case-sensitive and can only contain letters.
+
+## Basic Array Operations
+
+You can reverse an array's rows with [reverse](/docs/reverse).
+
+```uiua
+rev[1 2 3] # Run to format!
+```
+
+```uiua
+⇌[1_2_3 4_5_6]
+```
+
+You can concatenate two arrays with [join](/docs/join).
+
+```uiua
+⊂1 [2 3 4]
+⊂[1 2 3] [4 5 6]
+```
+
+You can make two arrays the rows of a new array with [couple](/docs/couple).
+
+```uiua
+⊟[1 2 3] [4 5 6]
+```
+
+You can get the first row of an array with [first](/docs/first) (or the last row with [last](/docs/last)).
+
+```uiua
+⊢[1 2 3]
+```
+
+```uiua
+fir[1_2_3 4_5_6]
+```
+
+```uiua
+lst "hello"
+```
+
+[take](/docs/take) and [drop](/docs/drop) can be used to get just part of an array.
+
+```uiua
+↙3 [1 2 3 4 5]
+↘3 [1 2 3 4 5]
+```
+
+[reshape](/docs/reshape) changes the shape of an array while keeping the elements in the same order.
+
+```uiua
+↯3_3 .⇡9
+```
+
+[transpose](/docs/transpose) rotates the axes of an array.
+
+```uiua
+trans.[1_2_3 4_5_6]
+```
+
+Uiua has a lot of built-in functions like these. You can explore their documentation on the [main docs page](/docs#functions).
+
+## Functions
+
+If you bind a name with `←` and the code on the right does not have enough arguments to run, the code will be bound as a function and will not run until the name is used.
+
+```uiua
+F ← +1
+F5
+```
+
+```uiua
+👋 ← ⊂"Hello, "
+👋"World"
+```
+
+## Modifiers
+Modifiers (called operators or adverbs in some other array languages) are functions that take other functions as arguments. Modifiers are parsed so that if their function argument(s) immediately follow them, the function is run inside the modifier rather than before it.
+
+[reduce](/docs/reduce) is a modifier many array-language aficionados will be familiar with. It takes its function and applies it "between" the items of an array.
+
+One basic use of [reduce](/docs/reduce) is to sum an array.
+
+```uiua
+/+ [1 2 3 4 5]
+```
+
+It works on multi-dimensional arrays too! In this case, it adds each row to the next, effectively summing along the columns.
+
+```uiua
+/+ .[1_2_3 4_5_6 7_8_9]
+```
+
+This works with any function. For example, you can use [max](/docs/max) instead of [add](/docs/add) to get the maximum of each column rather than the sum.
+
+```uiua
+/↥ [1_2_3 4_5_2 3_1_8]
+```
+
+[rows](/docs/rows) applies a function to each row of an array.
+
+```uiua
+x ← [1_2_3 4_5_6]
+ x
+ ⇌x
+≡⇌x
+```
+
+[rows](/docs/rows) also works *between* two arrays if it is given a dyadic function like [join](/docs/join).
+
+```uiua
+≡⊂ [1_2 3_4] [5_6 7_8]
+```
+
+There are a bunch of other modifiers that are useful in different situations. You can find a [list of them](/docs/modifier) on the main docs page.
+
+## Inline Functions
+If you need a more complex function for a modifier, you can make an inline function by surrounding code with `()`s.
+
+In this example, we use [table](/docs/table) call a function on all combinations of rows from two array.
+
+For each combination, we [reverse](/docs/reverse) the row from the first array, then [join](/docs/join) them together.
+
+```uiua
+⊞(⊂⇌) [1_2 3_4] [5 6 7]
+```
+
+## [fill](/docs/fill) and Nested Arrays
+Here is an array that cannot be constructed normally because its rows have different [shape](/docs/shape)s.
+
+```uiua should fail
+[1 2_3_4 5_6]
+```
+
+One way to make this array work is to use the [fill](/docs/fill) modifier. You give it a fill value and a function or array that would fail with mismatched shapes, and it will fill in the missing values with the fill value.
+
+```uiua
+⬚0[1 2_3_4 5_6]
+```
+
+[fill](/docs/fill) works with lots of functions. Another one is [take](/docs/take) when the amount you are taking is more than the length of the array.
+
+```uiua
+⬚π↙ 5 [1 2 3]
+```
+
+[fill](/docs/fill) is nice, but you don't always want to fill in the missing elements. Sometimes you need to mix values of different shapes or types in an array. To understand Uiua's solution to this problem, you must first understand its *array model*.
+
+Uiua has what is called a *flat* array model. Arrays must be rectangular and cannot mix types. However, the [box](/docs/box) function can turn any array into a *box* element that can be put in an array with other boxes. That value can then be extracted with [un](/docs/un)[box](/docs/box).
+
+```uiua
+[□1 □2_3_4 □5_6]
+```
+
+Having to use [box](/docs/box) on every value is kind of annoying, so there is a special syntax for [box](/docs/box) arrays that uses `{}`s instead of `[]`s.
+
+```uiua
+{1 2_3_4 5_6}
+```
+
+Pervasive functions work on [box](/docs/box)ed elements without needing to [un](/docs/un)[box](/docs/box) them.
+
+```uiua
++5 {1 2_3_4 5_6}
+```
+
+For more complex operations, you can use to use the [inventory](/docs/inventory) modifier, which calls a function on the content of each box.
+
+```uiua
+{"dog" "cat" "fish"}
+⍚(⊂⇌.).
+```
+
+## Inverses
+Uiua leans heavily into a feature present in some other array languages: *inverses*.
+
+The inverse of a function is the function that conceptually *undoes* it.
+
+[un](/docs/un) is the basic inversion modifier. It does the inverting behavior of its function.
+
+```uiua
+°⊟ [1_2_3 4_5_6]
+```
+
+```uiua
+°(+1) 5
+```
+
+```uiua
+ ⊢ {"abc" "d" "ef"}
+°□ ⊢ {"abc" "d" "ef"}
+```
+
+The [un](/docs/un)-inverse of a function must have the opposite number of arguments and outputs.
+
+[anti](/docs/anti) has a different constraint, and can be used to access some interesting inverses.
+
+```uiua
+ ↘ 2 [1 2 3 4 5]
+⌝↘ 2 [3 4 5]
+```
+
+```uiua
+ ⊏ [1 2 5] "abcdef"
+⬚@-⌝⊏ [1 2 5] "bcf"
+```
+
+[under](/docs/under) is probably Uiua's most powerful modifier. It calls it's first function, calls it's second function, then undoes its first.
+
+This is useful for everything from mathematics to string processing to automatically closing file handles.
+
+For example, [under](/docs/under) can easily generate a range between two numbers.
+
+```uiua
+⍜-⇡ 3 10
+```
+
+That example [subtract](/docs/subtract)s `3`, gets the [range](/docs/range), then [add](/docs/add)s `3` back.
+
+Here, we [multiply](/docs/multiply) only the numbers that correspond to `1`s in the mask
+
+```uiua
+⍜▽(×10) [1 0 1 1 0 0 1 0] [1 2 3 4 5 6 7 8]
+```
+
+Here, we get the [first](/docs/first) character of each word, capitalize them with [absolute value](/docs/absolute), then put them back.
+
+```uiua
+⍜⊜⊢⌵ ⊸≠@ "under is very useful!"
+```
+
+## Multimedia
+Uiua can natively generate images, audio, and GIFs.
+
+On this site, simply leaving an array on the stack that *looks* like image or audio data will display it.
+
+### Images
+Image data can either be a rank 2 array of grayscale pixel data or a rank 3 array of grayscale with alpha, RGB, or RGBA pixel data.
+
+This minimal example uses three different functions on x/y coordinates to generate RGB values and make a pretty gradient.
+
+```uiua
+⍉[⊞⊃⊃+-×].÷⟜⇡100
+```
+
+The Uiua logo is made with Uiua itself!
+
+```uiua
+LOGO
+```
+
+### Audio
+Audio data is just an array of numbers between -1 and 1. The numbers are interpreted as samples of a waveform.
+
+This example plays a series of notes.
+
+```uiua
+↯4[0 2 4 7 12 9 7 4]
+×220 ⁿ:2÷12
+÷2 ∿×τ ♭⍉⊞× ÷:⇡⁅÷8. &asr
+```
+
+### GIFs
+Any array whose rows can all be turned into images can be turned into a GIF.
+
+On this site, arrays that look like they should be GIFs will be displayed as GIFs. You can see some on the [main page](/).
+
+GIFs can be explicitly rendered with the [`&gifs`](/docs/&gifs) function.
+
+## Next Steps
+If you want a more in-depth introduction to Uiua, you can check out the [tutorial](/tutorial/introduction).
+
+For information on installing the native Uiua interpreter, see the [install page](/install).
+
+For information on specific functions and modifiers, see the [functions section](/docs#functions) of the main docs page.
+
+To see some cool examples, click through the editor at the top of the [home page](/). There are also some interesting, longer examples in the [main Uiua repository on GitHub](https://github.com/uiua-lang/uiua/tree/main/examples).
diff --git a/site/blog/second-class-functions-html.html b/site/blog/second-class-functions-html.html
new file mode 100644
index 000000000..3e30b29ce
--- /dev/null
+++ b/site/blog/second-class-functions-html.html
@@ -0,0 +1,11 @@
+
+
+
+
+
You can read this post with full editor features here.
2023-12-15
People often ask why Uiua doesn't have first-class functions. That is, functions that can be put on the stack and in arrays.
In the beginning, functions were normal array elements. Modifiers popped their functions from the stack like regular values. Functions could be put in arrays, and lists of functions even had some special uses. There was a ! call function which called the top function on the stack. Boxes were not even a dedicated type. They were just functions that took no arguments and returned a single value.
However, as Uiua's development continued, the language began to rely more and more on stack signatures being well-defined. This property catches errors early, enables some optimizations, and allows modifiers to behave differently depending on their function's siganture. That last point lets us avoid having multiple modifiers that work the same way but on different numbers of arguments. For example, Factor has the words bi, 2bi, 3bi, tri, 2tri, and 3tri. Uiua can express all of these and more with just
+ ⊃ fork
+ .
Unfortunately, having first-class functions was at odds with this design. Because functions could be put into arrays and (conditionally) moved around on the stack, the compiler was not able to determine the signature of a function that called a function value. This meant that anywhere the ! call function was used needed a signature annotation nearby, which you better hope was correct, or the code would break somewhere else. It also incurred additional interpreter overhead to get the functions from arrays and made certain types of optimizations impossible.
Other than these design and implementation concerns, the ability to move functions around on the stack made code much harder to read when it was used. You had to keep in your mind not only the values, but the functions that worked on them as well. They were another value you had to deal with, and the related stack manipulation could get quite messy.
And so I settled on a different approach. Functions were removed as an element type and were put elsewhere in the interpreter. Boxes became a type in their own right. The ! call function was removed, and ! was repurposed to be part of defining custom modifiers. Custom modifiers capture the primary use case of first-class functions: injecting some variable code into a function. While they are technically more limited, their uniform structure makes them easier to both read and write. This change also massively simplified the interpreter, as well as the complexity of the language itself.
Despite the downgrading of functions to second-class status, it should be noted that I do like functional programming languages. I just don't think that first-class functions are a good fit for Uiua. In practice, first-class functions are mostly unnecessary if you have higher-order functions, which array languages have had for decades. APL's operators, J's adverbs and conjunctions, and BQN and Uiua's modifiers are all versions of higher-order functions. They allow the mapping, reduction, and general transformation of data in the same way that first-class functions do in other languages.
Now if only I could find a way to get rid of boxes...
\ No newline at end of file
diff --git a/site/blog/subscripts-html.html b/site/blog/subscripts-html.html
new file mode 100644
index 000000000..936bac793
--- /dev/null
+++ b/site/blog/subscripts-html.html
@@ -0,0 +1,102 @@
+
+
+
+
+
You can read this post with full editor features here.
2024-11-25
If you get into any level of mathematics above a middle school level, you're likely to encounter notation that involves subscripts: little numbers or letters that sit across the baseline of the text and indicate different things about the thing to their left.
One common use of subscripts is to indicate indices. In many (perhaps the majoriy of?) programming languages, the subscript index notation of mathematics is replaced with the familiar [] square bracket syntax. Even APL, of which Uiua is a descendent, uses square brackets for this purpose. This is a nice, uniform syntax that is - critically - easy to type on an ASCII keyboard. But it loses a bit of the art, beauty, and expressiveness of mathematical notation.
Subscripts in Uiua
Uiua's formatter and its embrace of Unicode glyphs free it from the contraints many other languages have. This makes it possible to explore powerful and/or aesthetic syntactic constructs that would either be impossible or cumbersome to express in other languages. Look no further than the fancy module delimiters.
Uiua has actually allowed subscript numbers in identifiers for a while. Since identifiers cannot contain regular digits, this allows you to put numbers in them anyway.
Md₅ ← ∘ # TODO
+Sha₂₅₆ ← ∘ # TODO
Subscripts for use beyond identifiers were originally proposed in the Uiua discord as almost a joke. A whimsical syntax for modifying the behavior of certain functions and modifiers. But people got to talking about what could be possible, and I implemented subscripts as an experimental feature. At time of writing, subscripts have just been stabilized.
Uiua subscripts are written with two underscores __ followed by some digits. They can also be negative. The formatter will convert this into nice unicode subscript digits.
# Try formatting!
++__1 5 # 6
+×₂ 12 # 24 6
But what are they for? In the example above, they are equivalent to just not using them at all. For mathematical operators, they are only really good for reducing the number of parentheses needed. This is valuable in its own right for readability, but it is not reason enough to add an entire syntax for it.
However, subscripts on some functions and modifiers allow you to express things that would otherwise be impossible.
A brief history of Uiua's rank functionality
Uiua has gone through a few iterations of ways to express operating at a certain rank of an array. The other array languages simply have a rank operator that allows the direct specification of the rank to operate at. This approach works and is very general. At one point, Uiua had something similar in a modifier called ≑ level. This took a number or list of numbers indicating the ranks to operate at, as well as the function to operate on the array. While this worked, something about it never sat right with me. In an array language, the structure and rank of an array are, in most cases, the structure of the computation itself. There's something odd about having some numbers in your code that refer to actual numbers, and then other numbers that refer to the computation.
The first attempt to alleviate this discomfort I felt was the infamous Ocean Notation. It was a series of glyphs that had special parsing rules but whose function was only to create rank lists for use with level ≑ level. This mostly eliminated rank-indicating numbers from the code. While this system was kind of neat, it added too many new symbols for the programmer to learn with very little payoff, and it was not general enough to handle all cases.
≑ level was eventually replaced with Uiua's current system involving
+ ≡ rows
+ and
+ ¤ fix
+ . This system is simple, composable, and easy to learn. However, it cannot handle a common use of rank in other array languages: how do you operate on rank-N subarrays of an array of arbitrary rank? To fill this hole, the ☇ rerank function was added. This set the rank of the rows of an array to the given number. This also worked, and the system was complete.
But there were those numbers in the code again. You'd most often write ☇1 or ☇2 to change the rank of an array, collapsing the leading dimensions, sometimes temporarily. The thing is, you never need this number to be dynamic. It is always a number sitting there in the code itself, a static value, known at compile time. Sometimes it had to be relative to the rank of the array, in which case you would use a static negative number, but a static value nontheless.
Some uses of subscripts
As subscripts were experimented with, we realized that they could replace all uses of ☇ rerank.
Want to collapse an array to a certain rank? That's subscripted
+ ♭ deshape
+ .
What do you do when you want to collect some number of values from the stack into an array? The previous direction was to use []s or {}s with
+ ⊙ dip
+ and
+ ∘ identity
+ .
How do you take the Nth root of a number? Previously, you'd have to raise to the power of the reciprocal. Now you can just use subscripted
+ √ sqrt
+ .
ⁿ÷:1 3 125 # 5
+√₃ 125 # 5 5
Something similarly useful happens with
+ ⁅ round
+ .
⍜×⁅ 1e3 π # 3.142
+⁅₃ π # 3.142 3.142
Subscripts also solve the infamous problem of calling
+ ∩ both
+ on 3 sets of arguments.
[∩₃+ 1 2 3 4 5 6] # [3 7 11]
This is all to not even mention all the ways that subscripts simply help avoid parentheses, which reduces line noise and makes code easier to read.
You can find a full list of all the currently implemented subscripts here.
Going forward
One thing not listed above, and which is certainly more subjective, is that subscripts are pretty. They evoke the beauty of mathematical notation, a little number that you write to augment meaning. They make me smile! 😊
Much more is possible as well. One likely future use of subscripts is as a way to indicate non-base-10 numeric literals. Also, allowing for non-numeric subscripts would open up a whole new avenue of exploration.
I hope you enjoy this new feature. It is available in the online pad and in the latest release of the native interpreter.
\ No newline at end of file
diff --git a/site/blog/uiua-0.10.0-html.html b/site/blog/uiua-0.10.0-html.html
new file mode 100644
index 000000000..19be7d1d2
--- /dev/null
+++ b/site/blog/uiua-0.10.0-html.html
@@ -0,0 +1,66 @@
+
+
+
+
+
This release contains so many changes, improvements, and new features that I thought it deserved a blog post.From here on, major releases will be announced in this way.
While there are many changes, I want to highlight a few of them here.
Pattern Matching
Using
+ ° un
+ on a constant value will now match a pattern. When used with
+ ⍣ try
+ , this can be used to conditionally match, extract, and process values.
The new &clget and &clset functions provide access to the clipboard.
The interpreter's built-in language server now supports many more features.
There are a ton more! Again, you can read the full changelog here.
💖
As always, I'd like to thank everyone who contributed to this release, whether by directly contributing code, reporting bugs, or just using Uiua and providing feedback.
Uiua is in many ways a novel and unique language, and I think it is only through our collective effort that we can properly explore its design space.
With your help, I hope to continue to improve Uiua to the point of stability.
\ No newline at end of file
diff --git a/site/blog/uiua-0.11.0-html.html b/site/blog/uiua-0.11.0-html.html
new file mode 100644
index 000000000..dc76bc2a3
--- /dev/null
+++ b/site/blog/uiua-0.11.0-html.html
@@ -0,0 +1,174 @@
+
+
+
+
+
Uiua is a general purpose, stack-based, array-oriented programming language with a focus on tacit code.
While this release does not have any major new features, it extends the functionality of many primitives, optimizes many common patterns, and fixes a number of bugs.
+ / reduce
+ takes a dyadic function and applies it "between" all rows of an array.
/+ [1 2 3 4 5] # 15
+ / reduce
+ can now take multiple arguments if its function takes more than two arguments. Additional arguments are interspersed between the rows and are passed above the main array on the stack.
/(⊂⊂) 0 [1 2 3 4] # [1 0 2 0 3 0 4]
This is particularly useful when used with
+ ◇ content
+ and
+ ⊂ join
+ to intersperse a delimiter between a list of strings.
Array swizzles are written with a ⋊ followed by some letters. Rows from the array that correspond to the letters will be put on the stack. ⋊ formats from '' when followed by letters.
Swizzles are experimental and may change in future versions as their place in the language is explored.
The New Pad
Much of the code for the Uiua website pad has been rewritten. This new pad uses less custom behavior and should work better in more browsers.
If you are reading this on the Uiua website (with full editor features), then all the examples above use this new pad!
💗
Thank you as always to everyone who uses Uiua and helps with its development! Your enthusiasm for the language gives me life.
A special thanks to all of Uiua's sponsors for their continued support 🥰
Again, you can find the full changelog for this release here.
You can join the Uiua Discord to chat about the language, ask questions, or get help.
\ No newline at end of file
diff --git a/site/blog/uiua-0.12.0-html.html b/site/blog/uiua-0.12.0-html.html
new file mode 100644
index 000000000..72411756b
--- /dev/null
+++ b/site/blog/uiua-0.12.0-html.html
@@ -0,0 +1,256 @@
+
+
+
+
+
As always, a heartfelt thank-you to everyone in the Uiua community! Your contributions are what make Uiua great.
If you want to support Uiua's development, you can become one of its excellent sponsors!
Again, you can find the full changelog for this release here.
You can join the Uiua Discord to chat about the language, ask questions, or get help.
Media Constants
A final fun note!
A few built-in image and audio constants have been added. These are useful for testing and demonstrating image and audio functions!
Logo
+▽⟜≡▽ 0.5 # Scales the image down
+Lena
+▽⟜≡▽ 0.5
+Music
\ No newline at end of file
diff --git a/site/blog/uiua-0.13.0-html.html b/site/blog/uiua-0.13.0-html.html
new file mode 100644
index 000000000..a92407dbe
--- /dev/null
+++ b/site/blog/uiua-0.13.0-html.html
@@ -0,0 +1,221 @@
+
+
+
+
+
Top-level
+ ⍤ assert
+ ions are now interpreted as tests in some contexts. This includes in the website pad, or the uiua watch and uiua test commands, but not the uiua run command.
The native interpreter has two new commands: uiua find and uiua doc.
uiua find searches a file or directory for a string of formatted uiua code. This is useful when you cannot easily type some glyphs in your editor's default find interface.
uiua doc prints documentation for a function or modifier. That's it! It is the same documentation that is present on the website.
# Experimental!
This release added a lot of experimental features. Experimental features are not guaranteed to make it into the stable language, but they are added so they can be tried out.
Experimental features can be enabled by putting an # Experimental! comment at the top of a file.
Subscripts are an interesting way to augment the behavior of a function or modifier.
Subscript numbers may immediately follow a glyph. These can be typed with __ followed by some digits.
Also, check out Omnikar's awesome uiua-plot library for making plots and graphs in Uiua!
💟
Thanks as always to everyone in the Uiua community, and to Uiua's generous GitHub Sponsors!
Again, you can find the full changelog for this release here.
You can join the Uiua Discord to chat about the language, ask questions, or get help. We also do code challenges and discuss language features!
🐈⬛🐈
▽⟜≡▽ 0.5 Cats
\ No newline at end of file
diff --git a/site/blog/what-will-1-look-like-html.html b/site/blog/what-will-1-look-like-html.html
new file mode 100644
index 000000000..8d1db4a8e
--- /dev/null
+++ b/site/blog/what-will-1-look-like-html.html
@@ -0,0 +1,5 @@
+
+
+
+
+
You can read this post with full editor features here.
2024-01-19
The Uiua pad page prominently displays the words "Uiua is not yet stable". And so it has been asked: when will Uiua be stable? What features will it have? Is there a roadmap?
This post is to organize and present my thoughts on the future of Uiua.
Stability
Uiua will be made officially stable only after it has been unofficially stable for some time. That is, not until no breaking changes have been made for a long time.
The following language features will need to be nailed down before Uiua can ever be stable.
Stack manipulation
I think working with the stack, at least for up to 3 values, has become mostly pretty nice. However, things start to get complicated when working with more values, as is often necessary. There is some design work to be done here, and it's not out of the question that a very small amount of non-tacitness could be introduced to improve this.
The experimental bind modifier is a potential solution to this problem.
There is a balance to be struc between Uiua's goal of tacitness and its goal of being ergonomic. While the beauty of fully tacit code is a worthy goal, some problems involve data flows that are inherently complex, and so some kind of labeling system may be necessary to make such problems workable.
Box Ergonomics
While I've explored alternatives, I've come to the conclusion that nested arrays are a necessary pest. The data we work with is often nested or ragged, and while there are ways to represent such data with flat structures, those representations are cumbersome in their own ways.
And so boxes are likely here to stay. However, I do think some design work can be done to improve their ergonomics. Currently, Uiua's boxes are very similar to J's, but I think it may be worth it to make their usage a bit more implicit in some cases, closer to the nested arrays of APL or BQN.
System APIs
The current system functions are useful and mostly work. There are definitely implementation gaps which need to be filled. There are a good number of missing filesystem operations, and some other things like UDP sockets and proper interaction with child processes still need to be implemented.
FFI
An FFI system similar to BQN's is planned. This will allow Uiua to call into C libraries and will enable a lot more functionality.
\ No newline at end of file
diff --git a/src/algorithm/loops.rs b/src/algorithm/loops.rs
index cedab3745..f73b4a599 100644
--- a/src/algorithm/loops.rs
+++ b/src/algorithm/loops.rs
@@ -625,10 +625,7 @@ fn multi_partition_indices(markers: &Array) -> Vec<(isize, Vec)> {
*c = 0;
}
}
- let mut shape_muls: Vec = markers
- .shape()
- .iter()
- .rev()
+ let mut shape_muls: Vec = (markers.shape().iter().rev())
.scan(1, |mul, &dim| {
let prev = *mul;
*mul *= dim;