@jsenv/dom 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/dist/jsenv_dom.js +262 -330
  2. package/package.json +2 -4
  3. package/index.js +0 -124
  4. package/src/attr/add_attribute_effect.js +0 -93
  5. package/src/attr/attributes.js +0 -32
  6. package/src/color/color_constrast.js +0 -69
  7. package/src/color/color_parsing.js +0 -319
  8. package/src/color/color_scheme.js +0 -28
  9. package/src/color/pick_light_or_dark.js +0 -34
  10. package/src/color/resolve_css_color.js +0 -60
  11. package/src/demos/3_columns_resize_demo.html +0 -84
  12. package/src/demos/3_rows_resize_demo.html +0 -89
  13. package/src/demos/aside_and_main_demo.html +0 -93
  14. package/src/demos/coordinates_demo.html +0 -450
  15. package/src/demos/document_autoscroll_demo.html +0 -517
  16. package/src/demos/drag_gesture_constraints_demo.html +0 -701
  17. package/src/demos/drag_gesture_demo.html +0 -1047
  18. package/src/demos/drag_gesture_element_to_impact_demo.html +0 -445
  19. package/src/demos/drag_reference_element_demo.html +0 -480
  20. package/src/demos/flex_details_set_demo.html +0 -302
  21. package/src/demos/flex_details_set_demo_2.html +0 -315
  22. package/src/demos/visible_rect_demo.html +0 -525
  23. package/src/element_signature.js +0 -100
  24. package/src/interaction/drag/constraint_feedback_line.js +0 -92
  25. package/src/interaction/drag/drag_constraint.js +0 -659
  26. package/src/interaction/drag/drag_debug_markers.js +0 -635
  27. package/src/interaction/drag/drag_element_positioner.js +0 -382
  28. package/src/interaction/drag/drag_gesture.js +0 -566
  29. package/src/interaction/drag/drag_resize_demo.html +0 -571
  30. package/src/interaction/drag/drag_to_move.js +0 -301
  31. package/src/interaction/drag/drag_to_resize_gesture.js +0 -68
  32. package/src/interaction/drag/drop_target_detection.js +0 -148
  33. package/src/interaction/drag/sticky_frontiers.js +0 -160
  34. package/src/interaction/event_marker.js +0 -14
  35. package/src/interaction/focus/active_element.js +0 -33
  36. package/src/interaction/focus/arrow_navigation.js +0 -599
  37. package/src/interaction/focus/element_is_focusable.js +0 -57
  38. package/src/interaction/focus/element_visibility.js +0 -111
  39. package/src/interaction/focus/find_focusable.js +0 -21
  40. package/src/interaction/focus/focus_group.js +0 -91
  41. package/src/interaction/focus/focus_group_registry.js +0 -12
  42. package/src/interaction/focus/focus_nav.js +0 -12
  43. package/src/interaction/focus/focus_nav_event_marker.js +0 -14
  44. package/src/interaction/focus/focus_trap.js +0 -105
  45. package/src/interaction/focus/tab_navigation.js +0 -128
  46. package/src/interaction/focus/tests/focus_group_skip_tab_test.html +0 -206
  47. package/src/interaction/focus/tests/tree_focus_test.html +0 -304
  48. package/src/interaction/focus/tests/tree_focus_test.jsx +0 -261
  49. package/src/interaction/focus/tests/tree_focus_test_preact.html +0 -13
  50. package/src/interaction/isolate_interactions.js +0 -161
  51. package/src/interaction/keyboard.js +0 -26
  52. package/src/interaction/scroll/capture_scroll.js +0 -47
  53. package/src/interaction/scroll/is_scrollable.js +0 -159
  54. package/src/interaction/scroll/scroll_container.js +0 -110
  55. package/src/interaction/scroll/scroll_trap.js +0 -44
  56. package/src/interaction/scroll/scrollbar_size.js +0 -20
  57. package/src/interaction/scroll/wheel_through.js +0 -138
  58. package/src/iterable_weak_set.js +0 -66
  59. package/src/position/dom_coords.js +0 -340
  60. package/src/position/offset_parent.js +0 -15
  61. package/src/position/position_fixed.js +0 -15
  62. package/src/position/position_sticky.js +0 -213
  63. package/src/position/sticky_rect.js +0 -79
  64. package/src/position/visible_rect.js +0 -486
  65. package/src/pub_sub.js +0 -31
  66. package/src/size/can_take_size.js +0 -11
  67. package/src/size/details_content_full_height.js +0 -63
  68. package/src/size/flex_details_set.js +0 -974
  69. package/src/size/get_available_height.js +0 -22
  70. package/src/size/get_available_width.js +0 -22
  71. package/src/size/get_border_sizes.js +0 -14
  72. package/src/size/get_height.js +0 -4
  73. package/src/size/get_inner_height.js +0 -15
  74. package/src/size/get_inner_width.js +0 -15
  75. package/src/size/get_margin_sizes.js +0 -10
  76. package/src/size/get_max_height.js +0 -57
  77. package/src/size/get_max_width.js +0 -47
  78. package/src/size/get_min_height.js +0 -14
  79. package/src/size/get_min_width.js +0 -14
  80. package/src/size/get_padding_sizes.js +0 -10
  81. package/src/size/get_width.js +0 -4
  82. package/src/size/hooks/use_available_height.js +0 -27
  83. package/src/size/hooks/use_available_width.js +0 -27
  84. package/src/size/hooks/use_max_height.js +0 -10
  85. package/src/size/hooks/use_max_width.js +0 -10
  86. package/src/size/hooks/use_resize_status.js +0 -62
  87. package/src/size/resize.js +0 -695
  88. package/src/size/resolve_css_size.js +0 -32
  89. package/src/style/dom_styles.js +0 -97
  90. package/src/style/style_composition.js +0 -121
  91. package/src/style/style_controller.js +0 -345
  92. package/src/style/style_default.js +0 -153
  93. package/src/style/style_default_demo.html +0 -128
  94. package/src/style/style_parsing.js +0 -375
  95. package/src/transition/demos/animation_resumption_test.xhtml +0 -500
  96. package/src/transition/demos/height_toggle_test.xhtml +0 -515
  97. package/src/transition/dom_transition.js +0 -254
  98. package/src/transition/easing.js +0 -48
  99. package/src/transition/group_transition.js +0 -261
  100. package/src/transition/transform_style_parser.js +0 -32
  101. package/src/transition/transition_playback.js +0 -366
  102. package/src/transition/transition_timeline.js +0 -79
  103. package/src/traversal.js +0 -247
  104. package/src/ui_transition/demos/content_states_transition_demo.html +0 -628
  105. package/src/ui_transition/demos/smooth_height_transition_demo.html +0 -149
  106. package/src/ui_transition/demos/transition_testing.html +0 -354
  107. package/src/ui_transition/ui_transition.js +0 -1491
  108. package/src/utils.js +0 -69
  109. package/src/value_effect.js +0 -35
@@ -1,302 +0,0 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <title>Flex details set demo</title>
5
- <meta name="viewport" content="width=device-width, initial-scale=1" />
6
- <meta charset="utf-8" />
7
- <link rel="icon" href="data:," />
8
- </head>
9
- <body>
10
- <style>
11
- body {
12
- margin: 0;
13
- }
14
-
15
- * {
16
- box-sizing: border-box;
17
- }
18
-
19
- #app {
20
- margin: 10px;
21
- }
22
-
23
- .flex_details_set {
24
- display: flex;
25
- flex-direction: column;
26
-
27
- border: 1px solid black;
28
-
29
- display: flex;
30
- flex-direction: column;
31
- height: 60vh;
32
- box-sizing: content-box;
33
- width: 300px;
34
- margin-left: 100px;
35
- margin-top: 20px;
36
- }
37
-
38
- .flex_details {
39
- overflow: hidden;
40
- flex-shrink: 1;
41
- }
42
- .flex_details summary {
43
- user-select: none;
44
- cursor: pointer;
45
- height: 30px;
46
- /* display: flex; */
47
- align-items: center;
48
- }
49
- .flex_details_content {
50
- padding: 20px 10px;
51
- width: fit-content;
52
- background: lightgray;
53
- overflow-y: auto;
54
- scrollbar-gutter: stable both-edges;
55
- scrollbar-width: thin;
56
- }
57
- </style>
58
-
59
- <div id="app"></div>
60
-
61
- <script type="module" jsenv-type="module/jsx">
62
- import { render } from "preact";
63
- import { useRef, useLayoutEffect, useState } from "preact/hooks";
64
- import { initFlexDetailsSet } from "../size/flex_details_set.js";
65
-
66
- // eslint-disable-next-line no-unused-vars
67
- const App = () => {
68
- const ref = useRef();
69
-
70
- const detailsGroupRef = useRef();
71
- const [aHeight, aHeightSetter] = useState(0);
72
- const [bHeight, bHeightSetter] = useState(0);
73
- const [cHeight, cHeightSetter] = useState(0);
74
-
75
- const [resizableDetailsIdSet, setResizableDetailsIdSet] = useState(
76
- new Set(),
77
- );
78
-
79
- // to test: put sizes in local storage to see if that works
80
-
81
- useLayoutEffect(() => {
82
- const flexDetailsSet = initFlexDetailsSet(ref.current, {
83
- onResizableDetailsChange: (resizableDetailsIdSet) => {
84
- console.log("resizableDetailsIdSet", resizableDetailsIdSet);
85
- setResizableDetailsIdSet(resizableDetailsIdSet);
86
- },
87
- onSizeChange: (sizeChangeEntries) => {
88
- for (const { element, value } of sizeChangeEntries) {
89
- if (element.id === "a") {
90
- aHeightSetter(value);
91
- }
92
- if (element.id === "b") {
93
- bHeightSetter(value);
94
- }
95
- if (element.id === "c") {
96
- cHeightSetter(value);
97
- }
98
- }
99
- },
100
- });
101
- detailsGroupRef.current = flexDetailsSet;
102
- return flexDetailsSet.cleanup;
103
- }, []);
104
-
105
- const [detailsCount, detailsCountSetter] = useState(3);
106
-
107
- return (
108
- <>
109
- <fieldset>
110
- <legend>Flex details set controls</legend>
111
- <div>
112
- First details height{" "}
113
- <label>
114
- <strong>requested:</strong>
115
- <input
116
- type="number"
117
- style="width: 100px;"
118
- step="20"
119
- onInput={(e) => {
120
- detailsGroupRef.current.requestResize(
121
- document.querySelector("#a"),
122
- e.target.valueAsNumber,
123
- );
124
- }}
125
- />
126
- </label>{" "}
127
- <label>
128
- <strong>actual:</strong>
129
- <input
130
- type="number"
131
- style="width: 100px;"
132
- value={aHeight}
133
- readOnly
134
- />
135
- </label>
136
- </div>
137
- <div>
138
- Second details height{" "}
139
- <label>
140
- <strong>requested:</strong>
141
- <input
142
- type="number"
143
- style="width: 100px;"
144
- step="20"
145
- onInput={(e) => {
146
- detailsGroupRef.current.requestResize(
147
- document.querySelector("#b"),
148
- e.target.valueAsNumber,
149
- );
150
- }}
151
- />
152
- </label>{" "}
153
- <label>
154
- <strong>actual:</strong>
155
- <input
156
- type="number"
157
- style="width: 100px;"
158
- value={bHeight}
159
- readOnly
160
- />
161
- </label>
162
- </div>
163
- <div>
164
- Third details height{" "}
165
- <label>
166
- <strong>requested:</strong>
167
- <input
168
- type="number"
169
- style="width: 100px;"
170
- step="20"
171
- onInput={(e) => {
172
- detailsGroupRef.current.requestResize(
173
- document.querySelector("#c"),
174
- e.target.valueAsNumber,
175
- );
176
- }}
177
- />
178
- </label>{" "}
179
- <label>
180
- <strong>actual:</strong>
181
- <input
182
- type="number"
183
- style="width: 100px;"
184
- value={cHeight}
185
- readOnly
186
- />
187
- </label>
188
- </div>
189
- <br />
190
- <button
191
- onClick={() => {
192
- document.querySelector("#a").toggleAttribute("open");
193
- }}
194
- >
195
- Toggle first details
196
- </button>{" "}
197
- <button
198
- onClick={() => {
199
- document.querySelector("#b").toggleAttribute("open");
200
- }}
201
- >
202
- Toggle second details
203
- </button>{" "}
204
- <button
205
- onClick={() => {
206
- document.querySelector("#c").toggleAttribute("open");
207
- }}
208
- >
209
- Toggle third details
210
- </button>
211
- <br /> <br />
212
- <button
213
- onClick={() => {
214
- console.clear();
215
- }}
216
- >
217
- Clear console
218
- </button>
219
- <label>
220
- Two details
221
- <input
222
- type="checkbox"
223
- checked={detailsCount === 2}
224
- onChange={(e) => {
225
- if (e.target.checked) {
226
- detailsCountSetter(2);
227
- } else {
228
- detailsCountSetter(3);
229
- }
230
- }}
231
- />
232
- </label>
233
- </fieldset>
234
-
235
- <br />
236
- <div ref={ref} className="flex_details_set">
237
- <FlexDetails id="a" color="blue">
238
- This is the main content area. Lorem ipsum dolor sit amet,
239
- consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut
240
- labore et dolore magna aliqua. Ut enim ad minim veniam, quis
241
- nostrud exercitation. This is the main content area. Lorem ipsum
242
- dolor sit amet, consectetur adipiscing elit.
243
- </FlexDetails>
244
- <FlexDetails
245
- id="b"
246
- color="green"
247
- open
248
- resizable={resizableDetailsIdSet.has("b")}
249
- >
250
- This is the main content area. Lorem ipsum dolor sit amet,
251
- consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut
252
- labore et dolore magna aliqua. Ut enim ad minim veniam, quis
253
- nostrud exercitation.
254
- </FlexDetails>
255
- {detailsCount === 3 && (
256
- <FlexDetails
257
- id="c"
258
- color="red"
259
- open
260
- resizable={resizableDetailsIdSet.has("c")}
261
- >
262
- This is the main content area. Lorem ipsum dolor sit amet,
263
- consectetur adipiscing elit. Sed do eiusmod tempor incididunt
264
- ut labore et dolore magna aliqua. Ut enim ad minim veniam,
265
- quis nostrud exercitation. This is the main content area.
266
- </FlexDetails>
267
- )}
268
- </div>
269
- </>
270
- );
271
- };
272
-
273
- // eslint-disable-next-line no-unused-vars
274
- const FlexDetails = ({ id, color, children, open, resizable }) => {
275
- return (
276
- <>
277
- {resizable && (
278
- <div
279
- id={`${id}-resize-handle`}
280
- data-resize-handle={id}
281
- style="height: 20px; margin-top: -5px; background: orange; flex-shrink: 0;"
282
- ></div>
283
- )}
284
- <details
285
- className="flex_details"
286
- id={id}
287
- style={`background: ${color};`}
288
- open={open}
289
- data-resize={resizable ? "vertical" : undefined}
290
- data-min-height="80"
291
- >
292
- <summary>Summary</summary>
293
- <div className="flex_details_content">{children}</div>
294
- </details>
295
- </>
296
- );
297
- };
298
-
299
- render(<App />, document.querySelector("#app"));
300
- </script>
301
- </body>
302
- </html>
@@ -1,315 +0,0 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <title>Flex details set demo</title>
5
- <meta name="viewport" content="width=device-width, initial-scale=1" />
6
- <meta charset="utf-8" />
7
- <link rel="icon" href="data:," />
8
- </head>
9
- <body>
10
- <style>
11
- body {
12
- margin: 0;
13
- }
14
-
15
- * {
16
- box-sizing: border-box;
17
- }
18
-
19
- #app {
20
- display: flex;
21
- }
22
-
23
- aside {
24
- height: 100vh;
25
- width: 400px;
26
- }
27
-
28
- .flex_details_set {
29
- height: 100%;
30
- display: flex;
31
- flex-direction: column;
32
- border: 1px solid black;
33
- display: flex;
34
- flex-direction: column;
35
- box-sizing: content-box;
36
- }
37
-
38
- .flex_details {
39
- overflow: hidden;
40
- flex-shrink: 1;
41
- }
42
- .flex_details summary {
43
- user-select: none;
44
- cursor: pointer;
45
- height: 30px;
46
- /* display: flex; */
47
- align-items: center;
48
- }
49
- .flex_details_content {
50
- padding: 20px 10px;
51
- width: fit-content;
52
- background: lightgray;
53
- overflow-y: auto;
54
- scrollbar-gutter: stable both-edges;
55
- scrollbar-width: thin;
56
- }
57
- </style>
58
-
59
- <div id="app"></div>
60
-
61
- <script type="module" jsenv-type="module/jsx">
62
- import { render } from "preact";
63
- import { useRef, useLayoutEffect, useState } from "preact/hooks";
64
- import { initFlexDetailsSet } from "../size/flex_details_set.js";
65
-
66
- // eslint-disable-next-line no-unused-vars
67
- const App = () => {
68
- const ref = useRef();
69
-
70
- const detailsGroupRef = useRef();
71
- const [aHeight, aHeightSetter] = useState(0);
72
- const [bHeight, bHeightSetter] = useState(0);
73
- const [cHeight, cHeightSetter] = useState(0);
74
-
75
- const [resizableDetailsIdSet, setResizableDetailsIdSet] = useState(
76
- new Set(),
77
- );
78
-
79
- // to test: put sizes in local storage to see if that works
80
-
81
- useLayoutEffect(() => {
82
- const flexDetailsSet = initFlexDetailsSet(ref.current, {
83
- onResizableDetailsChange: (resizableDetailsIdSet) => {
84
- console.log("resizableDetailsIdSet", resizableDetailsIdSet);
85
- setResizableDetailsIdSet(resizableDetailsIdSet);
86
- },
87
- onSizeChange: (sizeChangeEntries) => {
88
- for (const { element, value } of sizeChangeEntries) {
89
- if (element.id === "a") {
90
- aHeightSetter(value);
91
- }
92
- if (element.id === "b") {
93
- bHeightSetter(value);
94
- }
95
- if (element.id === "c") {
96
- cHeightSetter(value);
97
- }
98
- }
99
- },
100
- });
101
- detailsGroupRef.current = flexDetailsSet;
102
- return flexDetailsSet.cleanup;
103
- }, []);
104
-
105
- const [detailsCount, detailsCountSetter] = useState(3);
106
-
107
- return (
108
- <>
109
- <aside>
110
- <div ref={ref} className="flex_details_set">
111
- <FlexDetails id="a" color="blue">
112
- This is the main content area. Lorem ipsum dolor sit amet,
113
- consectetur adipiscing elit. Sed do eiusmod tempor incididunt
114
- ut labore et dolore magna aliqua. Ut enim ad minim veniam,
115
- quis nostrud exercitation. This is the main content area.
116
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut
117
- enim ad minim veniam, quis nostrud exercitation. This is the
118
- main content area. Lorem ipsum dolor sit amet, consectetur
119
- adipiscing elit. Ut enim ad minim veniam, quis nostrud
120
- exercitation. This is the main content area. Lorem ipsum dolor
121
- sit amet, consectetur adipiscing elit. Ut enim ad minim
122
- veniam, quis nostrud exercitation. This is the main content
123
- area. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
124
- </FlexDetails>
125
- <FlexDetails
126
- id="b"
127
- color="green"
128
- open
129
- resizable={resizableDetailsIdSet.has("b")}
130
- >
131
- This is the main content area. Lorem ipsum dolor sit amet,
132
- consectetur adipiscing elit. Sed do eiusmod tempor incididunt
133
- ut labore et dolore magna aliqua. Ut enim ad minim veniam,
134
- quis nostrud exercitation. Ut enim ad minim veniam, quis
135
- nostrud exercitation. This is the main content area. Lorem
136
- ipsum dolor sit amet, consectetur adipiscing elit.
137
- </FlexDetails>
138
- {detailsCount === 3 && (
139
- <FlexDetails
140
- id="c"
141
- color="red"
142
- open
143
- resizable={resizableDetailsIdSet.has("c")}
144
- >
145
- This is the main content area. Lorem ipsum dolor sit amet,
146
- consectetur adipiscing elit. Sed do eiusmod tempor
147
- incididunt ut labore et dolore magna aliqua. Ut enim ad
148
- minim veniam, quis nostrud exercitation. This is the main
149
- content area.
150
- </FlexDetails>
151
- )}
152
- </div>
153
- </aside>
154
- <main>
155
- <fieldset>
156
- <legend>Flex details set controls</legend>
157
- <div>
158
- First details height{" "}
159
- <label>
160
- <strong>requested:</strong>
161
- <input
162
- type="number"
163
- style="width: 100px;"
164
- step="20"
165
- onInput={(e) => {
166
- detailsGroupRef.current.requestResize(
167
- document.querySelector("#a"),
168
- e.target.valueAsNumber,
169
- );
170
- }}
171
- />
172
- </label>{" "}
173
- <label>
174
- <strong>actual:</strong>
175
- <input
176
- type="number"
177
- style="width: 100px;"
178
- value={aHeight}
179
- readOnly
180
- />
181
- </label>
182
- </div>
183
- <div>
184
- Second details height{" "}
185
- <label>
186
- <strong>requested:</strong>
187
- <input
188
- type="number"
189
- style="width: 100px;"
190
- step="20"
191
- onInput={(e) => {
192
- detailsGroupRef.current.requestResize(
193
- document.querySelector("#b"),
194
- e.target.valueAsNumber,
195
- );
196
- }}
197
- />
198
- </label>{" "}
199
- <label>
200
- <strong>actual:</strong>
201
- <input
202
- type="number"
203
- style="width: 100px;"
204
- value={bHeight}
205
- readOnly
206
- />
207
- </label>
208
- </div>
209
- <div>
210
- Third details height{" "}
211
- <label>
212
- <strong>requested:</strong>
213
- <input
214
- type="number"
215
- style="width: 100px;"
216
- step="20"
217
- onInput={(e) => {
218
- detailsGroupRef.current.requestResize(
219
- document.querySelector("#c"),
220
- e.target.valueAsNumber,
221
- );
222
- }}
223
- />
224
- </label>{" "}
225
- <label>
226
- <strong>actual:</strong>
227
- <input
228
- type="number"
229
- style="width: 100px;"
230
- value={cHeight}
231
- readOnly
232
- />
233
- </label>
234
- </div>
235
- <br />
236
- <button
237
- onClick={() => {
238
- document.querySelector("#a").toggleAttribute("open");
239
- }}
240
- >
241
- Toggle first details
242
- </button>{" "}
243
- <button
244
- onClick={() => {
245
- document.querySelector("#b").toggleAttribute("open");
246
- }}
247
- >
248
- Toggle second details
249
- </button>{" "}
250
- <button
251
- onClick={() => {
252
- document.querySelector("#c").toggleAttribute("open");
253
- }}
254
- >
255
- Toggle third details
256
- </button>
257
- <br /> <br />
258
- <button
259
- onClick={() => {
260
- console.clear();
261
- }}
262
- >
263
- Clear console
264
- </button>
265
- <label>
266
- Two details
267
- <input
268
- type="checkbox"
269
- checked={detailsCount === 2}
270
- onChange={(e) => {
271
- if (e.target.checked) {
272
- detailsCountSetter(2);
273
- } else {
274
- detailsCountSetter(3);
275
- }
276
- }}
277
- />
278
- </label>
279
- </fieldset>
280
- </main>
281
- </>
282
- );
283
- };
284
-
285
- // eslint-disable-next-line no-unused-vars
286
- const FlexDetails = ({ id, color, children, open, resizable }) => {
287
- resizable = false;
288
- return (
289
- <>
290
- {resizable && (
291
- <div
292
- id={`${id}-resize-handle`}
293
- data-resize-handle={id}
294
- style="height: 20px; margin-top: -5px; background: orange; flex-shrink: 0;"
295
- ></div>
296
- )}
297
- <details
298
- className="flex_details"
299
- id={id}
300
- style={`background: ${color};`}
301
- open={open}
302
- data-resize={resizable ? "vertical" : undefined}
303
- data-min-height="150"
304
- >
305
- <summary>Summary</summary>
306
- <div className="flex_details_content">{children}</div>
307
- </details>
308
- </>
309
- );
310
- };
311
-
312
- render(<App />, document.querySelector("#app"));
313
- </script>
314
- </body>
315
- </html>