-
Notifications
You must be signed in to change notification settings - Fork 4
/
index.html
367 lines (321 loc) · 24.7 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
<!DOCTYPE html>
<html lang="en">
<head>
<title>Ariadne Reference</title>
<link rel="stylesheet" type="text/css" href="css/jazzy.css" />
<link rel="stylesheet" type="text/css" href="css/highlight.css" />
<meta charset="utf-8">
<script src="js/jquery.min.js" defer></script>
<script src="js/jazzy.js" defer></script>
<script src="js/lunr.min.js" defer></script>
<script src="js/typeahead.jquery.js" defer></script>
<script src="js/jazzy.search.js" defer></script>
</head>
<body>
<a title="Ariadne Reference"></a>
<header class="header">
<p class="header-col header-col--primary">
<a class="header-link" href="index.html">
Ariadne 0.7.0 Docs
</a>
(92% documented)
</p>
<p class="header-col--secondary">
<form role="search" action="search.json">
<input type="text" placeholder="Search documentation" data-typeahead>
</form>
</p>
<p class="header-col header-col--secondary">
<a class="header-link" href="https://github.com/DenTelezhkin/Ariadne">
<img class="header-icon" src="img/gh.png"/>
View on GitHub
</a>
</p>
<p class="header-col header-col--secondary">
<a class="header-link" href="dash-feed://https%3A%2F%2Fdentelezhkin.github.io%2FAriadne%2Fdocsets%2FAriadne.xml">
<img class="header-icon" src="img/dash.png"/>
Install in Dash
</a>
</p>
</header>
<p class="breadcrumbs">
<a class="breadcrumb" href="index.html">Ariadne Reference</a>
<img class="carat" src="img/carat.png" />
Ariadne Reference
</p>
<div class="content-wrapper">
<nav class="navigation">
<ul class="nav-groups">
<li class="nav-group-name">
<a class="nav-group-name-link" href="Classes.html">Classes</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/BaseTransition.html">BaseTransition</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/ChainableRoute.html">ChainableRoute</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/CurrentlyVisibleUpdatableViewFinder.html">CurrentlyVisibleUpdatableViewFinder</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/CurrentlyVisibleViewFinder.html">CurrentlyVisibleViewFinder</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/DismissTransition.html">DismissTransition</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/InstanceViewBuilder.html">InstanceViewBuilder</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/NavigationEmbeddingBuilder.html">NavigationEmbeddingBuilder</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/NavigationSingleViewEmbeddingBuilder.html">NavigationSingleViewEmbeddingBuilder</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes.html#/c:@M@Ariadne@objc(cs)NonBuildableView">NonBuildableView</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/NonBuilder.html">NonBuilder</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/PopNavigationTransition.html">PopNavigationTransition</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/PopNavigationTransition/Behavior.html">– Behavior</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/PopToRootNavigationTransition.html">PopToRootNavigationTransition</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/PresentationTransition.html">PresentationTransition</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/PushNavigationTransition.html">PushNavigationTransition</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/ReplaceNavigationTransition.html">ReplaceNavigationTransition</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/ReplaceNavigationTransition/Behavior.html">– Behavior</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/RootViewTransition.html">RootViewTransition</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/Route.html">Route</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/Router.html">Router</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SplitViewBuilder.html">SplitViewBuilder</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SplitViewCurrentlyVisibleViewFinder.html">SplitViewCurrentlyVisibleViewFinder</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SplitViewCurrentlyVisibleViewFinder/Kind.html">– Kind</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/TabBarEmbeddingBuilder.html">TabBarEmbeddingBuilder</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/UpdatingRoute.html">UpdatingRoute</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="Enums.html">Enumerations</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Enums/TransitionType.html">TransitionType</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="Extensions.html">Extensions</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)UIWindow">UIWindow</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="Protocols.html">Protocols</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/ContextUpdatable.html">ContextUpdatable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/RootViewProvider.html">RootViewProvider</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/Routable.html">Routable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/UpdatableViewFinder.html">UpdatableViewFinder</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/ViewControllerBuilder.html">ViewControllerBuilder</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/ViewFinder.html">ViewFinder</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/ViewTransition.html">ViewTransition</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="Structs.html">Structures</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Structs/AnyBuilder.html">AnyBuilder</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Structs/NonTransition.html">NonTransition</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="Typealiases.html">Type Aliases</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Typealiases.html#/s:7Ariadne11ViewBuildera">ViewBuilder</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Typealiases.html#/ViewController">ViewController</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Typealiases.html#/s:7Ariadne14ViewControllera">ViewController</a>
</li>
</ul>
</li>
</ul>
</nav>
<article class="main-content">
<section class="section">
<div class="section-content top-matter">
<p><img src="https://github.com/DenTelezhkin/Ariadne/workflows/CI/badge.svg" alt="CI">
<a href="http://codecov.io/github/DenTelezhkin/Ariadne?branch=master"><img src="http://codecov.io/github/DenTelezhkin/Ariadne/coverage.svg?branch=master" alt="codecov.io"></a>
<a href="https://dentelezhkin.github.io/Ariadne"><img src="https://img.shields.io/cocoapods/p/Ariadne.svg?style=flat" alt="Platform"></a>
<a href="https://img.shields.io/cocoapods/v/Ariadne.svg"><img src="https://img.shields.io/cocoapods/v/Ariadne.svg" alt="CocoaPods Compatible"></a>
<a href="https://github.com/apple/swift-package-manager"><img src="https://img.shields.io/badge/Swift%20Package%20Manager-compatible-brightgreen.svg" alt="Swift Package Manager compatible"></a>
<a href=""><img src="https://img.shields.io/packagist/l/doctrine/orm.svg" alt="Packagist"></a></p>
<p align="left">
<img height="160" src="https://github.com/DenTelezhkin/Ariadne/raw/master/logo.jpg" />
</p>
<h1 id='ariadne' class='heading'>Ariadne</h1>
<blockquote>
<p>Ariadne’s thread, named for the legend of Ariadne, is the solving of a problem with multiple apparent means of proceeding - such as a physical maze, a logic puzzle, or an ethical dilemma - through an exhaustive application of logic to all available routes.</p>
</blockquote>
<p align="right">
<a href="https://en.wikipedia.org/wiki/Ariadne%27s_thread_(logic)">Wikipedia</a>
</p>
<p>Ariadne is an extensible routing framework, built with composition and dependency injection principles in mind. It helps to create transitions and routes, that abstract away view controller building and presentation logic to make it reusable and compact.</p>
<h2 id='motivation' class='heading'>Motivation</h2>
<p>UIKit has a routing problem. All view controller presentation and dismissal methods happen in view controller, which a lot of times leads to bloated view controller, because all view controller building, dependency injection and transitions that also happen there.</p>
<p>This leads to massive view controllers, that cannot be easily tested, and code, that is hard to reuse across different view controller instances. One solution to those problems is to separate view controller building, and transition code in separate object, commonly called <code><a href="Classes/Router.html">Router</a></code>. And even though only some architectures like VIPER promote <code><a href="Classes/Router.html">Router</a></code> as required component, I would argue that app with any other architecture can be drastically improved by having at least some form of routing.</p>
<p>This is where <code>Ariadne</code> comes in. It is a framework, that provides view controller building mechanisms, transition and routing classes to abstract all this logic from view controller in architecture-agnostic way.</p>
<h1 id='example' class='heading'>Example</h1>
<p>Let’s say, for example, that you need to present user profile inside <code>UINavigationController</code>. Usually, in MVC app without any libraries, you would do something like this:</p>
<pre class="highlight swift"><code><span class="k">let</span> <span class="nv">storyboard</span> <span class="o">=</span> <span class="kt">UIStoryboard</span><span class="p">(</span><span class="nv">named</span><span class="p">:</span> <span class="s">"User"</span><span class="p">,</span> <span class="nv">bundle</span><span class="p">:</span> <span class="kc">nil</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">userController</span> <span class="o">=</span> <span class="n">storyboard</span><span class="o">.</span><span class="nf">instantiateViewController</span><span class="p">(</span><span class="nv">withIdentifier</span><span class="p">:</span> <span class="s">"UserViewController"</span><span class="p">)</span>
<span class="n">userController</span><span class="o">.</span><span class="n">user</span> <span class="o">=</span> <span class="n">user</span>
<span class="k">let</span> <span class="nv">navigation</span> <span class="o">=</span> <span class="kt">UINavigationController</span><span class="p">(</span><span class="nv">rootViewController</span><span class="p">:</span> <span class="n">userController</span><span class="p">)</span>
<span class="nf">present</span><span class="p">(</span><span class="n">navigation</span><span class="p">,</span> <span class="nv">animated</span><span class="p">:</span> <span class="kc">true</span><span class="p">)</span>
</code></pre>
<p>With Ariadne, this code is no longer tied to current view controller and can look like this:</p>
<pre class="highlight swift"><code><span class="k">let</span> <span class="nv">route</span> <span class="o">=</span> <span class="kt">Storyboards</span><span class="o">.</span><span class="kt">User</span><span class="o">.</span><span class="n">userViewController</span><span class="o">.</span><span class="n">builder</span><span class="o">.</span><span class="nf">embeddedInNavigation</span><span class="p">()</span><span class="o">.</span><span class="nf">presentRoute</span><span class="p">()</span>
<span class="n">router</span><span class="o">.</span><span class="nf">navigate</span><span class="p">(</span><span class="nv">to</span><span class="p">:</span> <span class="n">route</span><span class="p">,</span> <span class="nv">with</span><span class="p">:</span> <span class="n">user</span><span class="p">)</span>
</code></pre>
<blockquote>
<p>Note: this specific example requires SwiftGen integration, described in <a href="Guides/SwiftGen-integration.md">SwiftGen integration</a> guide.
Without SwiftGen <code>Storyboards.User.userViewController.builder</code> could be replaced by any custom view controller builder.</p>
</blockquote>
<h2 id='requirements' class='heading'>Requirements</h2>
<ul>
<li>iOS 10+</li>
<li>macOS 10.12+</li>
<li>tvOS 10+</li>
<li>watchOS 3+</li>
<li>Xcode 10 / Swift 4.2 and higher</li>
</ul>
<h2 id='installation' class='heading'>Installation</h2>
<h3 id='swift-package-manager-requires-xcode-11' class='heading'>Swift Package Manager(requires Xcode 11)</h3>
<ul>
<li>Add package into Project settings -> Swift Packages</li>
</ul>
<h3 id='cocoapods' class='heading'>CocoaPods</h3>
<pre class="highlight ruby"><code><span class="n">pod</span> <span class="s1">'Ariadne'</span>
</code></pre>
<h2 id='overview' class='heading'>Overview</h2>
<p><code>Ariadne</code> architecture fundamentally starts with <code><a href="Typealiases.html#/s:7Ariadne11ViewBuildera">ViewBuilder</a></code>. Because view controllers are so tightly coupled with their views on iOS, <code>UIViewController</code> is considered to be a view and is typealiased to <code><a href="Typealiases.html#/ViewController">ViewController</a></code>.</p>
<blockquote>
<p>Note: on watchOS <code><a href="Typealiases.html#/ViewController">ViewController</a></code> is a typealias for <code>WKInterfaceController</code>, and on macOS for <code>NSViewController</code> for similar reasons.</p>
</blockquote>
<p>Definition of <code><a href="Typealiases.html#/s:7Ariadne11ViewBuildera">ViewBuilder</a></code> is simple - it builds a <code><a href="Typealiases.html#/ViewController">ViewController</a></code> out of provided <code>Context</code>:</p>
<pre class="highlight swift"><code><span class="kd">protocol</span> <span class="kt">ViewBuilder</span> <span class="p">{</span>
<span class="kd">associatedtype</span> <span class="kt">ViewType</span><span class="p">:</span> <span class="kt">ViewController</span>
<span class="kd">associatedtype</span> <span class="kt">Context</span>
<span class="kd">func</span> <span class="nf">build</span><span class="p">(</span><span class="n">with</span> <span class="nv">context</span><span class="p">:</span> <span class="kt">Context</span><span class="p">)</span> <span class="k">throws</span> <span class="o">-></span> <span class="kt">ViewType</span>
<span class="p">}</span>
</code></pre>
<p>Out of the box, <code>Ariadne</code> provides builders for:</p>
<ul>
<li>UINavigationController</li>
<li>UITabBarController</li>
<li>UISplitViewController</li>
</ul>
<p>Second building block of the framework are <code><a href="Protocols/ViewTransition.html">ViewTransition</a></code> objects, that are needed to perform transition between views. Out of the box, following transitions are supported:</p>
<ul>
<li>UINavigationController transitions - push, pop, pop to root, pop to view controller, replace controllers in navigation stack</li>
<li>UIViewController presentations - present, dismiss</li>
<li>UIWindow root view controller transition to perform switch of the root view controller with animation.</li>
</ul>
<p><code><a href="Typealiases.html#/s:7Ariadne11ViewBuildera">ViewBuilder</a></code> and <code><a href="Protocols/ViewTransition.html">ViewTransition</a></code> object can be combined together to form a performable <code><a href="Classes/Route.html">Route</a></code>. For example, given <code>AlertBuilder</code>, here’s how creating a route for an alert might look like with <code>Ariadne</code>:</p>
<pre class="highlight swift"><code><span class="k">let</span> <span class="nv">alertRoute</span> <span class="o">=</span> <span class="kt">AlertBuilder</span><span class="p">()</span><span class="o">.</span><span class="nf">presentRoute</span><span class="p">()</span>
</code></pre>
<p>Notice how <code>presentRoute</code> method is called identically for <code>AlertBuilder</code> and any <code>UIViewController</code> builders. By leveraging protocol extensions on <code><a href="Typealiases.html#/s:7Ariadne11ViewBuildera">ViewBuilder</a></code> any transitions and routes can be reused on <code><a href="Typealiases.html#/s:7Ariadne11ViewBuildera">ViewBuilder</a></code> instance. To see examples of how <code><a href="Typealiases.html#/s:7Ariadne11ViewBuildera">ViewBuilder</a></code> protocol can be implemented and extended, please refer to <a href="Guides/Implementing-view-builders.md">Implementing view builders</a> guide.</p>
<p>Last, but not least, <code><a href="Classes/Router.html">Router</a></code> object ties everything together and allows you to actually perform routes:</p>
<pre class="highlight swift"><code><span class="n">router</span><span class="o">.</span><span class="nf">navigate</span><span class="p">(</span><span class="nv">to</span><span class="p">:</span> <span class="n">alertRoute</span><span class="p">,</span> <span class="nv">with</span><span class="p">:</span> <span class="n">alertModel</span><span class="p">,</span> <span class="nv">completion</span><span class="p">:</span> <span class="p">{</span> <span class="n">_</span> <span class="k">in</span>
<span class="c1">// Route has completed</span>
<span class="p">})</span>
</code></pre>
<p>Router uses <code><a href="Protocols/RootViewProvider.html">RootViewProvider</a></code> to find which view controller is a root one in a view hierarchy. On iOS and tvOS <code><a href="Protocols/RootViewProvider.html">RootViewProvider</a></code> is an interface for <code>UIWindow</code> and allows <code><a href="Classes/Router.html">Router</a></code> to get root view controller of view hierarchy. But on other platforms as well as application extensions UIApplication shared window is not accessible, and in that cases <code><a href="Protocols/RootViewProvider.html">RootViewProvider</a></code> may be different, for example in iMessage apps <code>MSMessagesAppViewController</code> may play similar role.</p>
<p><code><a href="Protocols/ViewFinder.html">ViewFinder</a></code> object traverses view hierarchy starting from root view to find view controller that is currently visible on screen. On iOS and tvOS <code>Ariadne</code> provides implementation of <code><a href="Classes/CurrentlyVisibleViewFinder.html">CurrentlyVisibleViewFinder</a></code> class, that recursively searches <code>UIViewController</code>, <code>UINavigationController</code> and <code>UITabBarController</code> to find which view controller is currently visible, but on other platforms and in other scenarios you might want to roll with your implementation or subclass of <code><a href="Classes/CurrentlyVisibleViewFinder.html">CurrentlyVisibleViewFinder</a></code>, if your view hierarchy contains other view controller containers.</p>
<h2 id='swiftgen-integration' class='heading'>SwiftGen integration</h2>
<p><a href="https://github.com/SwiftGen/SwiftGen">SwiftGen</a> is a powerful code generator, that can be used to set you free from using String-based API, that is cumbersome and error-prone. For example with storyboards, SwiftGen is able to generate code required for instantiating view controllers and makes this code to guarantee on compile-time that storyboard and view controller exist. <code>Ariadne</code> can build on top of that, producing a neat syntax for route building, like so:</p>
<pre class="highlight swift"><code><span class="k">let</span> <span class="nv">route</span> <span class="o">=</span> <span class="kt">Storyboards</span><span class="o">.</span><span class="kt">User</span><span class="o">.</span><span class="n">userViewController</span><span class="o">.</span><span class="n">builder</span><span class="o">.</span><span class="nf">embeddedInNavigation</span><span class="p">()</span><span class="o">.</span><span class="nf">presentRoute</span><span class="p">()</span>
</code></pre>
<p>To find out, how this can be achieved, refer to <a href="Guides/SwiftGen-integration.md">SwiftGen integration</a> guide.</p>
<h2 id='dependency-injection' class='heading'>Dependency injection</h2>
<p>Different applications can have completely different architectures and requirements. To see examples of simple dependency injection see <a href="Guides/SwiftGen-integration.md">SwiftGen integration</a> and for more advanced dependency injection with dependency containers like <a href="https://github.com/AliSoftware/Dip">Dip</a>, head to <a href="Guides/Advanced-dependency-injection.md">Advanced dependency injection examples</a> guide.</p>
<h2 id='vision' class='heading'>Vision</h2>
<p>To find out more about project future goals and vision, please read the <a href="VISION.md">Vision</a> document.</p>
<h2 id='documentation' class='heading'>Documentation</h2>
<p>You can find complete project documentation <a href="https://dentelezhkin.github.io/Ariadne/">here</a>.</p>
<h2 id='example-project' class='heading'>Example project</h2>
<p>iOS Example project can be found in Ariadne.xcodeproj and contains:</p>
<ul>
<li>Root view controller animated change</li>
<li>Push/pop, present/dismiss</li>
<li>Peek & Pop</li>
<li>Custom transition and presentation</li>
<li>Update currently visible view.</li>
</ul>
<h2 id='license' class='heading'>License</h2>
<p>Ariadne is released under a MIT license. See <a href="LICENSE">LICENSE</a> for more information.</p>
</div>
</section>
</article>
</div>
<section class="footer">
<p>© 2020 <a class="link" href="https://github.com/DenTelezhkin" target="_blank" rel="external">Denys Telezhkin</a>. All rights reserved. (Last updated: 2020-08-09)</p>
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.13.5</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external">Realm</a> project.</p>
</section>
</body>
</div>
</html>