src/doc: rename `tpl_namespace` in `html_namespace` also clean comments
[nit.git] / src / doc / html_templates / html_model.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # HTML templates for Nit model MEntities.
16 module html_model
17
18 import doc_base
19 import doc_down
20 import html_components
21 import html::bootstrap
22 import ordered_tree
23
24 redef class Location
25 # Github url based on this location
26 fun github(gitdir: String): String do
27 var base_dir = getcwd.join_path(gitdir).simplify_path
28 var file_loc = getcwd.join_path(file.filename).simplify_path
29 var gith_loc = file_loc.substring(base_dir.length + 1, file_loc.length)
30 return "{gith_loc}:{line_start},{column_start}--{line_end},{column_end}"
31 end
32 end
33
34 redef class MEntity
35 # ID used as a HTML unique ID and in file names.
36 #
37 # **Must** match the following (POSIX ERE) regular expression:
38 #
39 # ~~~POSIX ERE
40 # ^[A-Za-z_][A-Za-z0-9._-]*$
41 # ~~~
42 #
43 # That way, the ID is always a valid URI component and a valid XML name.
44 fun nitdoc_id: String is abstract
45
46 # URL of this entity’s Nitdoc page.
47 fun nitdoc_url: String is abstract
48
49 # Returns the mentity name without short signature.
50 #
51 # * MProject: `foo`
52 # * MGroup: `foo`
53 # * MModule: `foo`
54 # * MClass: `Foo[E]`
55 # * MClassDef: `Foo[E]`
56 # * MProperty: `foo(e)`
57 # * MPropdef: `foo(e)`
58 var html_name: String is lazy do return name.html_escape
59
60 # Returns a Link to the mentity `html_url`.
61 #
62 # Example: `<a href="html_url" title="mdoc.short_comment">html_short_name</a>
63 var html_link: Link is lazy do
64 var tpl = new Link(nitdoc_url, html_name)
65 var mdoc = mdoc_or_fallback
66 if mdoc != null then
67 tpl.title = mdoc.short_comment
68 end
69 return tpl
70 end
71
72 # Returns a Link to the mentity `nitdoc_id`.
73 #
74 # Example: `<a href="#nitdoc_id" title="mdoc.short_comment">html_short_name</a>
75 fun html_link_to_anchor: Link do
76 var tpl = new Link("#{nitdoc_id}", html_name)
77 var mdoc = mdoc_or_fallback
78 if mdoc != null then
79 tpl.title = mdoc.short_comment
80 end
81 return tpl
82 end
83
84 # Returns the list of keyword used in `self` declaration.
85 fun html_modifiers: Array[String] is abstract
86
87 # Returns the complete MEntity declaration decorated with HTML.
88 #
89 # * MProject: `project foo`
90 # * MGroup: `group foo`
91 # * MModule: `module foo`
92 # * MClass: `private abstract class Foo[E: Object]`
93 # * MClassDef: `redef class Foo[E]`
94 # * MProperty: `private fun foo(e: Object): Int`
95 # * MPropdef: `redef fun foo(e)`
96 fun html_declaration: Template do
97 var tpl = new Template
98 tpl.add "<span>"
99 tpl.add html_modifiers.join(" ")
100 tpl.add " "
101 tpl.add html_link
102 tpl.add "</span>"
103 return tpl
104 end
105
106 # Returns `self` namespace decorated with HTML links.
107 #
108 # * MProject: `mproject`
109 # * MGroup: `mproject(::group)`
110 # * MModule: `mgroup::mmodule`
111 # * MClass: `mproject::mclass`
112 # * MClassDef: `mmodule::mclassdef`
113 # * MProperty: `mclass::mprop`
114 # * MPropdef: `mclassdef:mpropdef`
115 fun html_namespace: Template is abstract
116
117 # A template article that briefly describe the entity
118 fun tpl_short_article: TplArticle do
119 var tpl = tpl_article
120 var mdoc = mdoc_or_fallback
121 if mdoc != null then
122 tpl.content = mdoc.tpl_short_comment
123 end
124 return tpl
125 end
126
127 # A template article that describe the entity
128 fun tpl_article: TplArticle do
129 var tpl = new TplArticle.with_title(nitdoc_id, tpl_title)
130 tpl.title_classes.add "signature"
131 tpl.subtitle = html_namespace
132 tpl.summary_title = html_name
133 return tpl
134 end
135
136 # A template definition of the mentity
137 # include name, sysnopsys, comment and namespace
138 fun tpl_definition: TplDefinition is abstract
139
140 # A li element that can go in a list
141 fun tpl_list_item: TplListItem do
142 var lnk = new Template
143 lnk.add new TplLabel.with_classes(tpl_css_classes)
144 lnk.add html_link
145 var mdoc = mdoc_or_fallback
146 if mdoc != null then
147 lnk.add ": "
148 lnk.add mdoc.tpl_short_comment
149 end
150 return new TplListItem.with_content(lnk)
151 end
152
153 var tpl_css_classes = new Array[String]
154
155 # Box title for this mentity
156 fun tpl_title: Template do
157 var title = new Template
158 title.add tpl_icon
159 title.add html_namespace
160 return title
161 end
162
163 # Icon that will be displayed before the title
164 fun tpl_icon: TplIcon do
165 var icon = new TplIcon.with_icon("tag")
166 icon.css_classes.add_all(tpl_css_classes)
167 return icon
168 end
169 end
170
171 redef class MConcern
172 # Return a li element for `self` that can be displayed in a concern list
173 private fun tpl_concern_item: TplListItem do
174 var lnk = new Template
175 lnk.add html_link_to_anchor
176 var mdoc = mdoc_or_fallback
177 if mdoc != null then
178 lnk.add ": "
179 lnk.add mdoc.tpl_short_comment
180 end
181 return new TplListItem.with_content(lnk)
182 end
183 end
184
185 redef class MProject
186 redef var nitdoc_id = name.to_cmangle is lazy
187 redef fun nitdoc_url do return root.nitdoc_url
188 redef var html_modifiers = ["project"]
189 redef fun html_namespace do return html_link
190
191 redef fun tpl_definition do
192 var tpl = new TplDefinition
193 var mdoc = mdoc_or_fallback
194 if mdoc != null then
195 tpl.comment = mdoc.tpl_comment
196 end
197 return tpl
198 end
199
200 redef fun tpl_css_classes do return ["public"]
201 end
202
203 redef class MGroup
204 redef var nitdoc_id is lazy do
205 if parent != null then
206 return "{parent.nitdoc_id}__{name.to_cmangle}"
207 end
208 return name.to_cmangle
209 end
210
211 redef fun nitdoc_url do return "group_{nitdoc_id}.html"
212 redef var html_modifiers = ["group"]
213
214 # Depends if `self` is root or not.
215 #
216 # * If root `mproject`.
217 # * Else `mproject::self`.
218 redef fun html_namespace do
219 var tpl = new Template
220 tpl.add mproject.html_namespace
221 if mproject.root != self then
222 tpl.add "::"
223 tpl.add html_link
224 end
225 return tpl
226 end
227
228 redef fun tpl_definition do
229 var tpl = new TplDefinition
230 var mdoc = mdoc_or_fallback
231 if mdoc != null then
232 tpl.comment = mdoc.tpl_comment
233 end
234 return tpl
235 end
236 end
237
238 redef class MModule
239 redef var nitdoc_id is lazy do
240 if mgroup != null then
241 if mgroup.mmodules.length == 1 then
242 return "{mgroup.nitdoc_id}-"
243 else
244 return "{mgroup.nitdoc_id}__{name.to_cmangle}"
245 end
246 end
247 return name.to_cmangle
248 end
249
250 redef fun nitdoc_url do return "module_{nitdoc_id}.html"
251 redef var html_modifiers = ["module"]
252
253 # Depends if `self` belongs to a MGroup.
254 #
255 # * If mgroup `mgroup::self`.
256 # * Else `self`.
257 redef fun html_namespace do
258 var tpl = new Template
259 if mgroup != null then
260 tpl.add mgroup.html_namespace
261 tpl.add "::"
262 end
263 tpl.add html_link
264 return tpl
265 end
266
267 redef fun tpl_definition do
268 var tpl = new TplClassDefinition
269 var mdoc = mdoc_or_fallback
270 if mdoc != null then
271 tpl.comment = mdoc.tpl_comment
272 end
273 return tpl
274 end
275
276 redef fun tpl_css_classes do return ["public"]
277 end
278
279 redef class MClass
280 redef var nitdoc_id = "{intro_mmodule.nitdoc_id}__{name.to_cmangle}" is lazy
281 redef fun nitdoc_url do return "class_{nitdoc_id}.html"
282 redef fun mdoc_or_fallback do return intro.mdoc
283
284 # Format: `Foo[E]`
285 redef var html_name is lazy do
286 var tpl = new Template
287 tpl.add name.html_escape
288 if arity > 0 then
289 tpl.add "["
290 var parameter_names = new Array[String]
291 for p in mparameters do
292 parameter_names.add(p.html_name)
293 end
294 tpl.add parameter_names.join(", ")
295 tpl.add "]"
296 end
297 return tpl.write_to_string
298 end
299
300 redef fun html_modifiers do return intro.html_modifiers
301 redef fun html_declaration do return intro.html_declaration
302
303 # Returns `mproject::self`.
304 redef fun html_namespace do
305 var tpl = new Template
306 tpl.add intro_mmodule.mgroup.mproject.html_namespace
307 tpl.add "::<span>"
308 tpl.add html_link
309 tpl.add "</span>"
310 return tpl
311 end
312
313 redef fun tpl_definition do return intro.tpl_definition
314
315 redef fun tpl_title do
316 var title = new Template
317 title.add tpl_icon
318 title.add html_link
319 return title
320 end
321
322 redef fun tpl_icon do return intro.tpl_icon
323
324 fun tpl_signature: Template do
325 var tpl = new Template
326 if arity > 0 then
327 tpl.add "["
328 var parameter_names = new Array[String]
329 for p in mparameters do
330 parameter_names.add(p.html_name)
331 end
332 tpl.add parameter_names.join(", ")
333 tpl.add "]"
334 end
335 return tpl
336 end
337
338 redef fun tpl_css_classes do return intro.tpl_css_classes
339 end
340
341 redef class MClassDef
342 redef var nitdoc_id = "{mmodule.nitdoc_id}__{name.to_cmangle}" is lazy
343 redef fun nitdoc_url do return "{mclass.nitdoc_url}#{nitdoc_id}"
344 redef fun mdoc_or_fallback do return mdoc or else mclass.mdoc_or_fallback
345
346 # Depends if `self` is an intro or not.
347 #
348 # * If intro contains the visibility and kind.
349 # * If redef contains the `redef` keyword and kind.
350 redef fun html_modifiers do
351 var res = new Array[String]
352 if not is_intro then
353 res.add "redef"
354 else
355 if mclass.visibility != public_visibility then
356 res.add mclass.visibility.to_s
357 end
358 end
359 res.add mclass.kind.to_s
360 return res
361 end
362
363 # Depends if `self` is an intro or not.
364 #
365 # For intro: `private abstract class Foo[E: Object]`
366 # For redef: `redef class Foo[E]`
367 # TODO change the implementation to correspond to the comment.
368 redef fun html_declaration do
369 var tpl = new Template
370 tpl.add "<span>"
371 tpl.add html_modifiers.join(" ")
372 tpl.add " "
373 tpl.add html_link
374 tpl.add tpl_signature
375 tpl.add "</span>"
376 return tpl
377 end
378
379 # Returns `mmodule::self`
380 redef fun html_namespace do
381 var tpl = new Template
382 tpl.add mmodule.html_namespace
383 tpl.add "::<span>"
384 tpl.add mclass.html_link
385 tpl.add "</span>"
386 return tpl
387 end
388
389 redef fun tpl_article do
390 var tpl = new TplArticle(nitdoc_id)
391 tpl.summary_title = "in {mmodule.html_name}"
392 tpl.title = html_declaration
393 tpl.title_classes.add "signature"
394 var title = new Template
395 title.add "in "
396 title.add mmodule.html_namespace
397 tpl.subtitle = title
398 var mdoc = mdoc_or_fallback
399 if mdoc != null then
400 tpl.content = mdoc.tpl_comment
401 end
402 return tpl
403 end
404
405 redef fun tpl_title do
406 var title = new Template
407 title.add tpl_icon
408 title.add html_link
409 return title
410 end
411
412 fun tpl_signature: Template do
413 var tpl = new Template
414 var mparameters = mclass.mparameters
415 if not mparameters.is_empty then
416 tpl.add "["
417 for i in [0..mparameters.length[ do
418 tpl.add "{mparameters[i].html_name}: "
419 tpl.add bound_mtype.arguments[i].tpl_signature
420 if i < mparameters.length - 1 then tpl.add ", "
421 end
422 tpl.add "]"
423 end
424 return tpl
425 end
426
427 redef fun tpl_definition do
428 var tpl = new TplClassDefinition
429 var mdoc = mdoc_or_fallback
430 if mdoc != null then
431 tpl.comment = mdoc.tpl_comment
432 end
433 return tpl
434 end
435
436 redef fun tpl_css_classes do
437 var set = new HashSet[String]
438 if is_intro then set.add "intro"
439 for m in mclass.intro.modifiers do set.add m.to_cmangle
440 for m in modifiers do set.add m.to_cmangle
441 return set.to_a
442 end
443
444 fun tpl_modifiers: Template do
445 var tpl = new Template
446 for modifier in modifiers do
447 if modifier == "public" then continue
448 tpl.add "{modifier.html_escape} "
449 end
450 return tpl
451 end
452 end
453
454 redef class MProperty
455 redef var nitdoc_id = "{intro_mclassdef.mclass.nitdoc_id}__{name.to_cmangle}" is lazy
456 redef fun nitdoc_url do return "property_{nitdoc_id}.html"
457 redef fun mdoc_or_fallback do return intro.mdoc
458 redef fun html_modifiers do return intro.html_modifiers
459 redef fun html_declaration do return intro.html_declaration
460
461 # Returns `mclass::self`.
462 redef fun html_namespace do
463 var tpl = new Template
464 tpl.add intro_mclassdef.mclass.html_namespace
465 tpl.add "::<span>"
466 tpl.add intro.html_link
467 tpl.add "</span>"
468 return tpl
469 end
470
471 fun tpl_signature: Template do return new Template
472
473 redef fun tpl_title do return intro.tpl_title
474
475 redef fun tpl_icon do return intro.tpl_icon
476
477 redef fun tpl_css_classes do return intro.tpl_css_classes
478 end
479
480 redef class MPropDef
481 redef var nitdoc_id = "{mclassdef.nitdoc_id}__{name.to_cmangle}" is lazy
482 redef fun nitdoc_url do return "{mproperty.nitdoc_url}#{nitdoc_id}"
483 redef fun mdoc_or_fallback do return mdoc or else mproperty.mdoc_or_fallback
484
485 # Depends if `self` is an intro or not.
486 #
487 # * If intro contains the visibility and kind.
488 # * If redef contains the `redef` keyword and kind.
489 redef fun html_modifiers do
490 var res = new Array[String]
491 if not is_intro then
492 res.add "redef"
493 else
494 if mproperty.visibility != public_visibility then
495 res.add mproperty.visibility.to_s
496 end
497 end
498 return res
499 end
500
501 # Depends if `self` is an intro or not.
502 #
503 # For intro: `private fun foo(e: Object): Bar is abstract`
504 # For redef: `redef fun foo(e) is cached`
505 # TODO change the implementation to correspond to the comment.
506 redef fun html_declaration do
507 var tpl = new Template
508 tpl.add "<span>"
509 tpl.add html_modifiers.join(" ")
510 tpl.add " "
511 tpl.add html_link
512 tpl.add tpl_signature
513 tpl.add "</span>"
514 return tpl
515 end
516
517 # Returns `mclassdef::self`
518 redef fun html_namespace do
519 var tpl = new Template
520 tpl.add mclassdef.html_namespace
521 tpl.add "::"
522 tpl.add html_link
523 return tpl
524 end
525
526 redef fun tpl_article do
527 var tpl = new TplArticle(nitdoc_id)
528 tpl.summary_title = "in {mclassdef.html_name}"
529 var title = new Template
530 title.add "in "
531 title.add mclassdef.html_link
532 tpl.title = title
533 tpl.subtitle = html_declaration
534 var mdoc = mdoc_or_fallback
535 if mdoc != null then
536 tpl.content = mdoc.tpl_comment
537 end
538 return tpl
539 end
540
541 redef fun tpl_definition do
542 var tpl = new TplDefinition
543 var mdoc = mdoc_or_fallback
544 if mdoc != null then
545 tpl.comment = mdoc.tpl_comment
546 end
547 return tpl
548 end
549
550 redef fun tpl_css_classes do
551 var set = new HashSet[String]
552 if is_intro then set.add "intro"
553 for m in mproperty.intro.modifiers do set.add m.to_cmangle
554 for m in modifiers do set.add m.to_cmangle
555 return set.to_a
556 end
557
558 fun tpl_modifiers: Template do
559 var tpl = new Template
560 for modifier in modifiers do
561 if modifier == "public" then continue
562 tpl.add "{modifier.html_escape} "
563 end
564 return tpl
565 end
566
567 fun tpl_signature: Template do return new Template
568
569 redef fun tpl_list_item do
570 var lnk = new Template
571 lnk.add new TplLabel.with_classes(tpl_css_classes.to_a)
572 var atext = html_link.text
573 var ahref = "{mclassdef.mclass.nitdoc_url}#{mproperty.nitdoc_id}"
574 var atitle = html_link.title
575 var anchor = new Link.with_title(ahref, atext, atitle)
576 lnk.add anchor
577 var mdoc = mdoc_or_fallback
578 if mdoc != null then
579 lnk.add ": "
580 lnk.add mdoc.tpl_short_comment
581 end
582 return new TplListItem.with_content(lnk)
583 end
584
585 fun tpl_inheritance_item: TplListItem do
586 var lnk = new Template
587 lnk.add new TplLabel.with_classes(tpl_css_classes.to_a)
588 lnk.add mclassdef.mmodule.html_namespace
589 lnk.add "::"
590 var atext = mclassdef.html_link.text
591 var ahref = "{mclassdef.mclass.nitdoc_url}#{mproperty.nitdoc_id}"
592 var atitle = mclassdef.html_link.title
593 var anchor = new Link.with_title(ahref, atext, atitle)
594 lnk.add anchor
595 var mdoc = mdoc_or_fallback
596 if mdoc != null then
597 lnk.add ": "
598 lnk.add mdoc.tpl_short_comment
599 end
600 var li = new TplListItem.with_content(lnk)
601 li.css_classes.add "signature"
602 return li
603 end
604 end
605
606 redef class MAttributeDef
607
608 redef fun html_modifiers do
609 var res = super
610 res.add "var"
611 return res
612 end
613
614 redef fun tpl_signature do
615 var tpl = new Template
616 if static_mtype != null then
617 tpl.add ": "
618 tpl.add static_mtype.tpl_signature
619 end
620 return tpl
621 end
622 end
623
624 redef class MMethod
625 redef fun tpl_signature do
626 var tpl = new Template
627 var params = new Array[String]
628 for param in intro.msignature.mparameters do
629 params.add param.name.html_escape
630 end
631 if not params.is_empty then
632 tpl.add "("
633 tpl.add params.join(", ")
634 tpl.add ")"
635 end
636 return tpl
637 end
638 end
639
640 redef class MMethodDef
641
642 # FIXME annotation should be handled in their own way
643 redef fun html_modifiers do
644 var res = super
645 if is_abstract then
646 res.add "abstract"
647 else if is_intern then
648 res.add "intern"
649 end
650 if mproperty.is_init then
651 res.add "init"
652 else
653 res.add "fun"
654 end
655 return res
656 end
657
658 redef fun tpl_signature do return msignature.tpl_signature
659 end
660
661 redef class MVirtualTypeProp
662 redef fun html_link do return mvirtualtype.html_link
663 redef fun tpl_signature do return html_link
664 end
665
666 redef class MVirtualTypeDef
667
668 redef fun html_modifiers do
669 var res = super
670 res.add "type"
671 return res
672 end
673
674 redef fun tpl_signature do
675 var tpl = new Template
676 if bound == null then return tpl
677 tpl.add ": "
678 tpl.add bound.tpl_signature
679 return tpl
680 end
681 end
682
683 redef class MType
684 fun tpl_signature: Template is abstract
685 end
686
687 redef class MClassType
688 redef fun html_link do return mclass.html_link
689 redef fun tpl_signature do return html_link
690 end
691
692 redef class MNullableType
693 redef fun tpl_signature do
694 var tpl = new Template
695 tpl.add "nullable "
696 tpl.add mtype.tpl_signature
697 return tpl
698 end
699 end
700
701 redef class MGenericType
702 redef fun tpl_signature do
703 var lnk = html_link
704 var tpl = new Template
705 tpl.add new Link.with_title(lnk.href, mclass.name.html_escape, lnk.title)
706 tpl.add "["
707 for i in [0..arguments.length[ do
708 tpl.add arguments[i].tpl_signature
709 if i < arguments.length - 1 then tpl.add ", "
710 end
711 tpl.add "]"
712 return tpl
713 end
714 end
715
716 redef class MParameterType
717 redef fun html_link do
718 return new Link.with_title("{mclass.nitdoc_url}#FT_{name.to_cmangle}", name, "formal type")
719 end
720 redef fun tpl_signature do return html_link
721 end
722
723 redef class MVirtualType
724 redef fun html_link do return mproperty.intro.html_link
725 redef fun tpl_signature do return html_link
726 end
727
728 redef class MSignature
729 redef fun tpl_signature do
730 var tpl = new Template
731 if not mparameters.is_empty then
732 tpl.add "("
733 for i in [0..mparameters.length[ do
734 tpl.add mparameters[i].tpl_signature
735 if i < mparameters.length - 1 then tpl.add ", "
736 end
737 tpl.add ")"
738 end
739 if return_mtype != null then
740 tpl.add ": "
741 tpl.add return_mtype.tpl_signature
742 end
743 return tpl
744 end
745 end
746
747 redef class MParameter
748 fun tpl_signature: Template do
749 var tpl = new Template
750 tpl.add "{name}: "
751 tpl.add mtype.tpl_signature
752 if is_vararg then tpl.add "..."
753 return tpl
754 end
755 end
756
757 redef class ConcernsTree
758
759 private var seen = new HashSet[MConcern]
760
761 redef fun add(p, e) do
762 if seen.has(e) then return
763 seen.add e
764 super(p, e)
765 end
766
767 fun to_tpl: TplList do
768 var lst = new TplList.with_classes(["list-unstyled", "list-definition"])
769 for r in roots do
770 var li = r.tpl_concern_item
771 lst.add_li li
772 build_list(r, li)
773 end
774 return lst
775 end
776
777 private fun build_list(e: MConcern, li: TplListItem) do
778 if not sub.has_key(e) then return
779 var subs = sub[e]
780 var lst = new TplList.with_classes(["list-unstyled", "list-definition"])
781 for e2 in subs do
782 if e2 isa MGroup and e2.is_root then
783 build_list(e2, li)
784 else
785 var sli = e2.tpl_concern_item
786 lst.add_li sli
787 build_list(e2, sli)
788 end
789 end
790 li.append lst
791 end
792 end
793
794
795 ################################################################################
796 # Additions to `model_ext`.
797
798 redef class MRawType
799 redef fun tpl_signature do
800 var tpl = new Template
801
802 for part in parts do
803 if part.target != null then
804 tpl.add part.target.as(not null).html_link
805 else
806 tpl.add part.text.html_escape
807 end
808 end
809 return tpl
810 end
811 end
812
813 redef class MInnerClass
814 redef fun nitdoc_url do return inner.nitdoc_url
815 redef fun tpl_signature do return inner.tpl_signature
816 end
817
818 redef class MInnerClassDef
819 redef fun nitdoc_url do return inner.nitdoc_url
820
821 redef fun html_link_to_anchor do return inner.html_link_to_anchor
822 redef fun html_link do return inner.html_link
823 redef fun tpl_signature do return inner.tpl_signature
824
825 redef fun tpl_definition do
826 var tpl = new TplClassDefinition
827 var mdoc = mdoc_or_fallback
828 if mdoc != null then
829 tpl.comment = mdoc.tpl_comment
830 end
831 return tpl
832 end
833 end