-
-
Notifications
You must be signed in to change notification settings - Fork 11
Add section for TSX #36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
9f77526
5f041de
58f5601
e7505e6
ac6ab35
0ddb5a6
5545b6e
3be690c
cfb5f34
3fc4e23
dd5a169
07ea4f3
bef2403
d77bb64
18c8d03
1b34947
b26bd4a
be73195
84b6c46
039d85f
3c5e9e8
1f0e45d
db934ea
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -5,9 +5,12 @@ Explanation, examples, and build notes on how to use JSX in your Mithril.js-base | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # JSX | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - [Description](#description) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - [Setup](#setup) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - [Setup JSX](#setup-jsx) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - [Production build](#production-build) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - [Using Babel with Webpack](#using-babel-with-webpack) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - [Setup TSX](#setup-tsx-jsx-in-typescript) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - [Enabling Fragments](#enable-fragments) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - [Using Closure Components in TSX](#using-closure-components-in-tsx) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - [Differences with React](#differences-with-react) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - [JSX vs hyperscript](#jsx-vs-hyperscript) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - [Tips and Tricks](#tips-and-tricks) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -58,9 +61,9 @@ m.render(document.body, <MyComponent />) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ### Setup | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ### Setup JSX | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| The simplest way to use JSX is via a [Babel](https://babeljs.io/) plugin. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| When using JavaScript, the simplest way to use JSX is via a [Babel](https://babeljs.io/) plugin. When using using [TypeScript](https://www.typescriptlang.org/) follow the [instructions below](#setup-tsx-jsx-in-typescript) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's move the "when using TypeScript" to the next section.
Suggested change
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I shortened it. But I do think its wise to link to TSX in this secion. A lot of times the term "JSX" is used for "TSX" interchangably (so is "JavaScript" for "TypeScript") and TypeScript users might stumble over this section and follow the wrong instructions. Tell me if you find that unnecessary and I should fully remove it |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Babel requires npm, which is automatically installed when you install [Node.js](https://nodejs.org/en/). Once npm is installed, create a project folder and run this command: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -241,6 +244,118 @@ See [the Webpack docs](https://webpack.js.org/plugins/provide-plugin/) for more | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ### Setup TSX (JSX in TypeScript) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Since TypeScript is already transpiled, Babel is not necessary. All you need to do is tell TypeScript how to handle JSX code correctly (more information about JSX in TypeScript [here](https://www.typescriptlang.org/docs/handbook/jsx.html)). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
JodliDev marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Add `jsx` and `jsxFactory` to `compilerOptions` in your `tsconfig.json`: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ```json | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "compilerOptions": { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "jsx": "react", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "jsxFactory": "m" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| This setup should be enough to get most JSX functionality working. But there are a few gotchas that you might want to fix as well: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #### Enabling Fragments | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
JodliDev marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| With the setup above, you will not be able to use Fragments (e.g. `<>bla</>`). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| To enable Fragments, first add `jsxFragmentFactory` to `compilerOptions` in your `tsconfig.json`: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ```json | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "compilerOptions": { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "jsxFragmentFactory": "m.fragment" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| `m.fragment` also needs to be defined globally. The easiest way of doing that, is adding the following line to the entry point of your application (depending on your project structure, that might be `src/index.ts`): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ```typescript | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| m.fragment = { view: (vNode: Vnode) => vNode.children } as any; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
JodliDev marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #### Using Closure Components in TSX | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
JodliDev marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| When using [Closure Components](components.md#closure-component-state) in JSX, TypeScript only expects an attribute object as a parameter for a Function Component. But Mithril provides a `Vnode` object instead. This leads to the IDE showing faulty parameters even though the JSX would compile correctly. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
JodliDev marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Example: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| The following code will compile correctly but show this error: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| TS2739: Type { greet: string; } is missing the following properties from type Vnode<{}, {}>: tag, attrs, state | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| TS2786: LoadingSpinner cannot be used as a JSX component. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ```typescript jsx | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
JodliDev marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| interface Attributes { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| greet: string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function ChildComponent(vNode: Vnode<Attributes>): m.Component<Attributes> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| view: <div>{vNode.attrs.greet}</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
JodliDev marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function ParentComponent() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| view: <div><ChildComponent greet="Hello World"/></div> //This line will compile correctly but shows the errors above | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+273
to
+288
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As requested in the previous review.
Suggested change
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you sure you want this change? As fas as I can see, semicolons after blocked return statements seem to be in line with the rest of the doc ( e.g. line 27, 396, 452, 481, 535) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
JodliDev marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| There are several options to circumvent that problem: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
JodliDev marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 1) Instead of `<div><ChildComponent greet="Hello World"/></div>`, use `<div>{m(ChildComponent, {greet: "Hello World"})}</div>` instead. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 2) Use [Class Components](components.md#class-component-state) instead. Class Components will not show any errors. But TypeScript will not be able to autocomplete or inspect attributes (in this example `greet` would be unknown when used in `ParentComponent`). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 3) Create a "translation function" (see `TranslatedComponent()` in the example below) to trick TypeScript. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
JodliDev marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| The following code will work without errors: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ```typescript jsx | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
JodliDev marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Use TranslatedComponent to create Closure Components that can be inspected by TypeScript. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export function TranslatedComponent<T>(create: m.ClosureComponent<T>) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you come up with a shorter name for this helper? Maybe something like
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree that I chose a poor name for that helper function. But I think |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return (attrs: T) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const vNode = attrs as m.Vnode<T>; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return create(vNode) as unknown as JSX.Element; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
JodliDev marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| interface Attributes { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| greet: string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| //We slightly altered the definition of ChildComponent by using TranslatedComponent() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
JodliDev marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const ChildComponent = TranslationdComponent<Attributes>(vNode => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
JodliDev marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| view: <div>{vNode.attrs.greet}</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
JodliDev marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function ParentComponent() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| view: <div><ChildComponent greet="Hello World"/></div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
JodliDev marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+314
to
+330
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As requested in the previous review.
Suggested change
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure this change is needed. See comment above |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| When you need generics for your closure component, you can use the following definition style: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
JodliDev marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ```typescript jsx | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function ChildComponentImpl<T>() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ... | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
JodliDev marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const ChildComponent = TranslatedComponent(ChildComponentImpl); //for TranslatedComponent, see above | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const jsx = <div><ChildComponent<SomeClass>/></div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
JodliDev marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ### Differences with React | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| JSX in Mithril has some subtle but important differences compared to React's JSX. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.