1
4
5# include "luametatex.h"
6
7
36
37insert_state_info lmt_insert_state = {
38 .inserts = NULL,
39 .insert_data = {
40 .minimum = min_insert_size,
41 .maximum = max_insert_size,
42 .size = memory_data_unset,
43 .step = stp_insert_size,
44 .allocated = 0,
45 .itemsize = sizeof(insert_record),
46 .top = 0,
47 .ptr = 0,
48 .initial = memory_data_unset,
49 .offset = 0,
50 .extra = 0,
51 },
52 .mode = unset_insert_mode,
53 .storing = 0,
54};
55
56typedef enum saved_insert_entries {
57 saved_insert_index_entry = 0,
58 saved_insert_data_entry = 0,
59 saved_insert_callback_entry = 0,
60 saved_insert_n_of_records = 1,
61} saved_insert_entries;
62
63# define saved_insert_index saved_value_1(saved_insert_index_entry)
64# define saved_insert_data saved_value_2(saved_insert_data_entry)
65# define saved_insert_callback saved_value_3(saved_insert_callback_entry)
66
67static inline void saved_inserts_initialize(void)
68{
69 saved_type(0) = saved_record_0;
70 saved_record(0) = insert_save_type;
71}
72
73void tex_show_insert_group(void)
74{
75 tex_print_str_esc("insert");
76 tex_print_int(saved_insert_index);
77}
78
79int tex_show_insert_record(void)
80{
81 tex_print_str("insert ");
82 switch (saved_type(0)) {
83 case saved_record_0:
84 tex_print_format("index %i", saved_insert_index);
85 break;
86 case saved_record_1:
87 tex_print_format("data %i", saved_insert_data);
88 break;
89 case saved_record_2:
90 tex_print_format("callback %i", saved_insert_callback);
91 break;
92 default:
93 return 0;
94 }
95 return 1;
96}
97
98void tex_initialize_inserts(void)
99{
100 insert_record *tmp = aux_allocate_clear_array(sizeof(insert_record), lmt_insert_state.insert_data.minimum, 1);
101 if (tmp) {
102 lmt_insert_state.inserts = tmp;
103 lmt_insert_state.insert_data.allocated = lmt_insert_state.insert_data.minimum;
104 lmt_insert_state.insert_data.top = lmt_insert_state.insert_data.minimum;
105 lmt_insert_state.insert_data.ptr = 0;
106 } else {
107 tex_overflow_error("inserts", lmt_insert_state.insert_data.minimum);
108 }
109}
110
111
115
116int tex_valid_insert_id(halfword n)
117{
118 switch (lmt_insert_state.mode) {
119 case index_insert_mode:
120 return (n >= 0 && n <= max_box_register_index);
121 case class_insert_mode:
122 if (n <= 0) {
123 tex_handle_error(
124 normal_error_type,
125 "In \\insertmode 2 you can't use zero as index.",
126 NULL
127 );
128 } else if (n <= lmt_insert_state.insert_data.ptr) {
129 return 1;
130 } else if (n < lmt_insert_state.insert_data.top) {
131 lmt_insert_state.insert_data.ptr = n;
132 return 1;
133 } else if (n < lmt_insert_state.insert_data.maximum && lmt_insert_state.insert_data.top < lmt_insert_state.insert_data.maximum) {
134 insert_record *tmp;
135 int top = n + lmt_insert_state.insert_data.step;
136 if (top > lmt_insert_state.insert_data.maximum) {
137 top = lmt_insert_state.insert_data.maximum;
138 }
139 tmp = aux_reallocate_array(lmt_insert_state.inserts, sizeof(insert_record), top, 1);
140 if (tmp) {
141 size_t extra = ((size_t) top - lmt_insert_state.insert_data.top) * sizeof(insert_record);
142 memset(&tmp[lmt_insert_state.insert_data.top + 1], 0, extra);
143
144 lmt_insert_state.inserts = tmp;
145 lmt_insert_state.insert_data.allocated = top;
146 lmt_insert_state.insert_data.top = top;
147 lmt_insert_state.insert_data.ptr = n;
148 return 1;
149 }
150 }
151 tex_overflow_error("inserts", lmt_insert_state.insert_data.maximum);
152 }
153 return 0;
154}
155
156scaled tex_get_insert_limit(halfword i)
157{
158 if (tex_valid_insert_id(i)) {
159 return lmt_insert_state.mode == index_insert_mode ? insert_maxheight(i) : lmt_insert_state.inserts[i].limit;
160 } else {
161 return 0;
162 }
163}
164
165halfword tex_get_insert_multiplier(halfword i)
166{
167 if (tex_valid_insert_id(i)) {
168 return lmt_insert_state.mode == index_insert_mode ? insert_multiplier(i) : lmt_insert_state.inserts[i].multiplier;
169 } else {
170 return 0;
171 }
172}
173
174halfword tex_get_insert_penalty(halfword i)
175{
176 if (tex_valid_insert_id(i)) {
177 return lmt_insert_state.mode == index_insert_mode ? floating_penalty_par : lmt_insert_state.inserts[i].penalty;
178 } else {
179 return 0;
180 }
181}
182
183halfword tex_get_insert_maxdepth(halfword i)
184{
185 if (tex_valid_insert_id(i)) {
186 return lmt_insert_state.mode == index_insert_mode ? split_max_depth_par : lmt_insert_state.inserts[i].maxdepth;
187 } else {
188 return 0;
189 }
190}
191
192halfword tex_get_insert_distance(halfword i)
193{
194 if (tex_valid_insert_id(i)) {
195 return lmt_insert_state.mode == index_insert_mode ? insert_distance(i) : lmt_insert_state.inserts[i].distance;
196 } else {
197 return 0;
198 }
199}
200
201static inline halfword tex_aux_insert_box(halfword i)
202{
203 if (tex_valid_insert_id(i)) {
204 return lmt_insert_state.mode == index_insert_mode ? insert_content(i) : lmt_insert_state.inserts[i].content;
205 } else {
206 return null;
207 }
208}
209
210scaled tex_get_insert_height(halfword i)
211{
212 halfword b = tex_aux_insert_box(i);
213 return b ? box_height(b) : 0;
214}
215
216scaled tex_get_insert_depth(halfword i)
217{
218 halfword b = tex_aux_insert_box(i);
219 return b ? box_depth(b) : 0;
220}
221
222scaled tex_get_insert_width(halfword i)
223{
224 halfword b = tex_aux_insert_box(i);
225 return b ? box_width(b) : 0;
226}
227
228halfword tex_get_insert_content(halfword i)
229{
230 return tex_aux_insert_box(i);
231}
232
233scaled tex_get_insert_line_height(halfword i)
234{
235 if (lmt_insert_state.mode == class_insert_mode && tex_valid_insert_id(i)) {
236 return lmt_insert_state.inserts[i].lineheight;
237 } else {
238 return 0;
239 }
240}
241
242scaled tex_get_insert_line_depth(halfword i)
243{
244 if (lmt_insert_state.mode == class_insert_mode && tex_valid_insert_id(i)) {
245 return lmt_insert_state.inserts[i].linedepth;
246 } else {
247 return 0;
248 }
249}
250scaled tex_get_insert_stretch(halfword i)
251{
252 if (lmt_insert_state.mode == class_insert_mode && tex_valid_insert_id(i)) {
253 return lmt_insert_state.inserts[i].stretch;
254 } else {
255 return 0;
256 }
257}
258
259scaled tex_get_insert_shrink(halfword i)
260{
261 if (lmt_insert_state.mode == class_insert_mode && tex_valid_insert_id(i)) {
262 return lmt_insert_state.inserts[i].shrink;
263 } else {
264 return 0;
265 }
266}
267
268halfword tex_get_insert_storage(halfword i)
269{
270 if (lmt_insert_state.mode == class_insert_mode && tex_valid_insert_id(i)) {
271 return has_insert_option(i, insert_option_storing);
272 } else {
273 return 0;
274 }
275}
276
277void tex_set_insert_limit(halfword i, scaled v)
278{
279 if (tex_valid_insert_id(i)) {
280 switch (lmt_insert_state.mode) {
281 case index_insert_mode: insert_maxheight(i) = v; break;
282 case class_insert_mode: lmt_insert_state.inserts[i].limit = v; break;
283 }
284 }
285}
286
287void tex_set_insert_multiplier(halfword i, halfword v)
288{
289 if (tex_valid_insert_id(i)) {
290 switch (lmt_insert_state.mode) {
291 case index_insert_mode: insert_multiplier(i) = v; break;
292 case class_insert_mode: lmt_insert_state.inserts[i].multiplier = v; break;
293 }
294 }
295}
296
297void tex_set_insert_penalty(halfword i, halfword v)
298{
299 if (tex_valid_insert_id(i) && lmt_insert_state.mode == class_insert_mode) {
300 lmt_insert_state.inserts[i].options = set_insert_option(lmt_insert_state.inserts[i].options, insert_option_penalty);
301 lmt_insert_state.inserts[i].penalty = v;
302 }
303}
304
305void tex_set_insert_maxdepth(halfword i, halfword v)
306{
307 if (tex_valid_insert_id(i) && lmt_insert_state.mode == class_insert_mode) {
308 lmt_insert_state.inserts[i].options = set_insert_option(lmt_insert_state.inserts[i].options, insert_option_maxdepth);
309 lmt_insert_state.inserts[i].maxdepth = v;
310 }
311}
312
313void tex_set_insert_distance(halfword i, halfword v)
314{
315 if (tex_valid_insert_id(i)) {
316 int d = null;
317 switch (lmt_insert_state.mode) {
318 case index_insert_mode:
319 d = insert_distance(i);
320 insert_distance(i) = v;
321 break;
322 case class_insert_mode:
323 d = lmt_insert_state.inserts[i].distance;
324 lmt_insert_state.inserts[i].distance = v;
325 break;
326 }
327 tex_flush_node(d);
328 }
329}
330
331void tex_set_insert_height(halfword i, scaled v)
332{
333 halfword b = tex_aux_insert_box(i);
334 if (b) {
335 box_height(b) = v;
336 }
337}
338
339void tex_set_insert_depth(halfword i, scaled v)
340{
341 halfword b = tex_aux_insert_box(i);
342 if (b) {
343 box_depth(b) = v;
344 }
345}
346
347void tex_set_insert_width(halfword i, scaled v)
348{
349 halfword b = tex_aux_insert_box(i);
350 if (b) {
351 box_width(b) = v;
352 }
353}
354
355void tex_set_insert_content(halfword i, halfword v)
356{
357
358 switch (lmt_insert_state.mode) {
359 case index_insert_mode: insert_content(i) = v; break;
360 case class_insert_mode: if (tex_valid_insert_id(i)) { lmt_insert_state.inserts[i].content = v; } break;
361 }
362}
363
364void tex_set_insert_line_height(halfword i, scaled v)
365{
366 if (lmt_insert_state.mode == class_insert_mode && tex_valid_insert_id(i)) {
367 lmt_insert_state.inserts[i].lineheight = v;
368 }
369}
370
371void tex_set_insert_line_depth(halfword i, scaled v)
372{
373 if (lmt_insert_state.mode == class_insert_mode && tex_valid_insert_id(i)) {
374 lmt_insert_state.inserts[i].linedepth = v;
375 }
376}
377
378void tex_set_insert_stretch(halfword i, scaled v)
379{
380 if (lmt_insert_state.mode == class_insert_mode && tex_valid_insert_id(i)) {
381 lmt_insert_state.inserts[i].stretch = v;
382 }
383}
384
385void tex_set_insert_shrink(halfword i, scaled v) {
386 if (lmt_insert_state.mode == class_insert_mode && tex_valid_insert_id(i)) {
387 lmt_insert_state.inserts[i].shrink = v;
388 }
389}
390
391void tex_set_insert_storage(halfword i, halfword v)
392{
393 if (lmt_insert_state.mode == class_insert_mode && tex_valid_insert_id(i)) {
394 lmt_insert_state.inserts[i].options = v
395 ? set_insert_option(lmt_insert_state.inserts[i].options, insert_option_storing)
396 : unset_insert_option(lmt_insert_state.inserts[i].options, insert_option_storing);
397 }
398}
399
400void tex_wipe_insert(halfword i) {
401 if (lmt_insert_state.mode == class_insert_mode && i >= 0 && i <= lmt_insert_state.insert_data.ptr) {
402
403 halfword b = lmt_insert_state.inserts[i].content;
404 if (b) {
405 tex_flush_node(b);
406 lmt_insert_state.inserts[i].content = null;
407 }
408 }
409}
410
411halfword lmt_get_insert_distance(halfword i, int slot)
412{
413 int callback_id = lmt_callback_defined(insert_distance_callback);
414 if (callback_id != 0) {
415 halfword replacement = null;
416 lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "dd->N", i, slot, &replacement);
417 if (replacement) {
418 return replacement;
419 } else {
420 halfword distance = null;
421 switch (lmt_insert_state.mode) {
422 case index_insert_mode:
423 distance = insert_distance(i);
424 break;
425 case class_insert_mode:
426 if (tex_valid_insert_id(i)) {
427 distance = lmt_insert_state.inserts[i].distance;
428 }
429 break;
430 }
431 if (distance) {
432 return tex_copy_node(distance);
433 }
434 }
435 }
436 return tex_new_glue_spec_node(null);
437}
438
439halfword tex_get_insert_progress(halfword i)
440{
441 if (tex_valid_insert_id(i)) {
442 halfword p = page_insert_head;
443 while (p && i >= insert_index(node_next(p))) {
444 p = node_next(p);
445 if (p == page_insert_head) {
446 break;
447 }
448 }
449 return insert_index(p) == i ? insert_total_height(p) : 0;
450 } else {
451 return 0;
452 }
453}
454
455
456
457halfword tex_scan_insert_index(void)
458{
459 halfword index = 0;
460 switch (lmt_insert_state.mode) {
461 case unset_insert_mode:
462 lmt_insert_state.mode = index_insert_mode;
463
464 case index_insert_mode:
465 index = tex_scan_box_register_number();
466 if (index == output_box_par) {
467 tex_handle_error(
468 normal_error_type,
469 "You can't \\insert%i",
470 output_box_par,
471 "I'm changing to \\insert0; box \\outputbox is special."
472 );
473 index = 0;
474 }
475 break;
476 case class_insert_mode:
477 index = tex_scan_integer(0, NULL, NULL);
478 if (! tex_valid_insert_id(index)) {
479 index = 0;
480 }
481 break;
482 }
483 return index;
484}
485
486void tex_set_insert_mode(halfword mode)
487{
488 if (lmt_insert_state.mode == unset_insert_mode && (mode == index_insert_mode || mode == class_insert_mode)) {
489 lmt_insert_state.mode = mode;
490 } else if (mode != lmt_insert_state.mode) {
491 tex_handle_error(
492 normal_error_type,
493 "Bad \\insertmode (%i)",
494 mode,
495 "This mode can be set once and has value 1 or 2. It will be automatically\n"
496 "set when \\insert is used."
497 );
498 }
499}
500
501int tex_insert_is_void(halfword i)
502{
503 halfword b = tex_aux_insert_box(i);
504 return (! b) || box_list(b) == null;
505}
506
507
508
509int tex_insert_stored(void)
510{
511 return lmt_insert_state.head != null;
512}
513
514void tex_insert_restore(halfword n)
515{
516 if (lmt_insert_state.tail) {
517 tex_couple_nodes(lmt_insert_state.tail, n);
518 } else {
519 lmt_insert_state.head = n;
520 }
521 lmt_insert_state.tail = n;
522}
523
524void tex_insert_store(halfword i, halfword n)
525{
526 if (tex_get_insert_storage(i)) {
527 tex_insert_restore(n);
528 }
529}
530
531
532
533void tex_dump_insert_data(dumpstream f) {
534 dump_int(f, lmt_insert_state.mode);
535 dump_int(f, lmt_insert_state.insert_data.ptr);
536 dump_int(f, lmt_insert_state.insert_data.top);
537 dump_things(f, lmt_insert_state.inserts[0], lmt_insert_state.insert_data.ptr);
538}
539
540void tex_undump_insert_data(dumpstream f) {
541 insert_record *tmp;
542 undump_int(f, lmt_insert_state.mode);
543 undump_int(f, lmt_insert_state.insert_data.ptr);
544 undump_int(f, lmt_insert_state.insert_data.top);
545 tmp = aux_allocate_clear_array(sizeof(insert_record), lmt_insert_state.insert_data.top, 1);
546 if (tmp) {
547 lmt_insert_state.inserts = tmp;
548 lmt_insert_state.insert_data.allocated = lmt_insert_state.insert_data.top;
549 undump_things(f, lmt_insert_state.inserts[0], lmt_insert_state.insert_data.ptr);
550 } else {
551 tex_overflow_error("inserts", lmt_insert_state.insert_data.top);
552 }
553}
554
555
558
559void tex_run_insert(void)
560{
561 int brace = 0;
562 halfword callback = 0;
563 halfword data = 0;
564 halfword index = -1;
565 while (1) {
566 switch (tex_scan_character("cdiCDI", 1, 1, 1)) {
567 case 0:
568 goto DONE;
569 case 'c': case 'C':
570 if (tex_scan_mandate_keyword("callback", 1)) {
571 callback = tex_scan_integer(0, NULL, NULL);
572 }
573 break;
574 case 'd': case 'D':
575
576 if (tex_scan_mandate_keyword("data", 1)) {
577 data = tex_scan_integer(0, NULL, NULL);
578 }
579 break;
580 case 'i': case 'I':
581 if (tex_scan_mandate_keyword("index", 1)) {
582 index = tex_scan_insert_index();
583 }
584 break;
585 case '{':
586 brace = 1;
587 goto DONE;
588 default:
589 goto DONE;
590 }
591 }
592 DONE:
593 if (index < 0) {
594 index = tex_scan_insert_index();
595 }
596 saved_inserts_initialize();
597 saved_insert_index = index;
598 saved_insert_data = data;
599 saved_insert_callback = callback;
600 lmt_save_state.save_stack_data.ptr += saved_insert_n_of_records;
601 tex_new_save_level(insert_group);
602 if (! brace) {
603 tex_scan_left_brace();
604 }
605 tex_normal_paragraph(insert_par_context);
606 tex_push_nest();
607 cur_list.mode = internal_vmode;
608 cur_list.prev_depth = ignore_depth_criterion_par;
609}
610
611void tex_finish_insert_group(void)
612{
613 if (! tex_wrapped_up_paragraph(insert_par_context, 0)) {
614 halfword p, q;
615 scaled d;
616 halfword f;
617 tex_end_paragraph(insert_group, insert_par_context);
618 q = tex_new_glue_node(split_top_skip_par, top_skip_code);
619 d = split_max_depth_par;
620 f = floating_penalty_par;
621 tex_unsave();
622 lmt_save_state.save_stack_data.ptr -= saved_insert_n_of_records;
623
624
625
626
627
628 p = node_next(cur_list.head);
629 tex_pop_nest();
630
634 p = tex_vpack(p, 0, packing_additional, max_dimension, direction_unknown, holding_none_option, NULL);
635 {
636 halfword index = saved_insert_index;
637 halfword data = saved_insert_data;
638 halfword callback = saved_insert_callback;
639 halfword insert = tex_new_node(insert_node, 0);
640 halfword maxdepth = tex_get_insert_maxdepth(index);
641 halfword floating = tex_get_insert_penalty(index);
642 if (tex_get_insert_storage(index)) {
643 tex_insert_store(index, insert);
644 } else {
645 tex_tail_append(insert);
646 }
647 insert_index(insert) = index;
648 insert_identifier(insert) = data;
649 insert_callback(insert) = callback;
650 insert_total_height(insert) = box_total(p);
651 insert_list(insert) = box_list(p);
652 insert_split_top(insert) = q;
653 insert_max_depth(insert) = has_insert_option(index, insert_option_maxdepth) ? d : maxdepth;
654 insert_float_cost(insert) = has_insert_option(index, insert_option_penalty) ? f : floating;
655 insert_line_height(insert) = tex_get_insert_line_height(index);
656 insert_line_depth(insert) = tex_get_insert_line_depth(index);
657 insert_stretch(insert) = tex_get_insert_stretch(index);
658 insert_shrink(insert) = tex_get_insert_shrink(index);
659 box_list(p) = null;
660 tex_flush_node(p);
661 if (tracing_inserts_par > 0) {
662 tex_begin_diagnostic();
663 tex_print_levels();
664 tex_print_format("[insert: setting, index %i, height %p, depth %p, penalty %i, topskip %Q]",
665 index, insert_total_height(insert), insert_max_depth(insert), insert_float_cost(insert), q, pt_unit);
666 if (tracing_inserts_par > 1) {
667 tex_print_node_list(insert_list(insert), "insert", show_box_depth_par, show_box_breadth_par);
668 }
669 tex_end_diagnostic();
670 }
671 }
672
673 if (lmt_nest_state.nest_data.ptr == 0) {
674 tex_build_page(insert_page_context, 0);
675 }
676 }
677}
678
679
683
684int tex_identify_inserts(halfword b, halfword cbk)
685{
686 halfword value = 0;
687 while (b) {
688 switch (node_type(b)) {
689 case hlist_node:
690 case vlist_node:
691 switch (node_subtype(b)) {
692 case hbox_list:
693 case container_list:
694 case unknown_list:
695 break;
696 case balance_slot_list:
697 goto DONE;
698 default:
699 return value;
700 }
701 break;
702 default:
703 return value;
704 }
705 b = box_list(b);
706 }
707 DONE:
708 if (b && node_type(b) == vlist_node) {
709 halfword current = box_list(b);
710 while (current) {
711 if (node_type(current) == insert_node) {
712 int callback = lmt_callback_defined(balance_insert_callback);
713 if (callback) {
714 ++lmt_balance_state.n_of_callbacks;
715 lmt_run_callback(lmt_lua_state.lua_instance, callback, "Nddd->",
716 current,
717 cbk,
718 insert_index(current),
719 insert_identifier(current)
720 );
721 }
722 value |= has_inserts;
723 if (insert_list(current)) {
724 value |= has_inserts_with_content;
725 }
726 if (insert_total_height(current) > 0 && tex_get_insert_multiplier(insert_index(current)) > 0) {
727 value |= has_inserts_with_height;
728 }
729 }
730 current = node_next(current);
731 }
732 }
733 return value;
734}
735
736scaled tex_insert_height(halfword node)
737{
738
739 if (node && node_type(node) == insert_node) {
740 halfword multiplier = tex_get_insert_multiplier(insert_index(node));
741 halfword needed = insert_total_height(node);
742 if (multiplier > 0 && needed > 0) {
743 return tex_x_over_n(needed, scaling_factor) * multiplier;
744 }
745 }
746 return 0;
747}
748
749# define set_bit(bits,n) bits[n/8] |= (1 << (index % 8))
750# define get_bit(bits,n) (1 & (bits[index/8] >> (n % 8)))
751
752void tex_insert_reset_distances(void)
753{
754 for (int index = 0; index <= lmt_insert_state.insert_data.top; index++) {
755 if (lmt_insert_state.inserts[index].before) {
756 tex_flush_node(lmt_insert_state.inserts[index].before);
757 }
758 lmt_insert_state.inserts[index].before = null;
759 if (lmt_insert_state.inserts[index].inbetween) {
760 tex_flush_node(lmt_insert_state.inserts[index].inbetween);
761 }
762 lmt_insert_state.inserts[index].inbetween = null;
763 }
764}
765
766scaled tex_insert_distances(halfword first, halfword last, scaled *stretch, scaled *shrink)
767{
768 char bits[(max_n_of_inserts/8)+1] = { 0 };
769 int isfirst = 1;
770 scaled amount = 0;
771 halfword c = first;
772 while (c != last) {
773 if (node_type(c) == insert_node && insert_total_height(c) > 0 && tex_get_insert_multiplier(insert_index(c)) > 0) {
774 halfword distance = null;
775 halfword index = insert_index(c);
776 if (isfirst) {
777 if (lmt_insert_state.inserts[index].before) {
778 distance = lmt_insert_state.inserts[index].before;
779 } else {
780 distance = lmt_get_insert_distance(index, 1);
781 lmt_insert_state.inserts[index].before = distance;
782 }
783 isfirst = 0;
784 set_bit(bits,index);
785 } else if (insert_index(c) == index && ! get_bit(bits, index)) {
786 if (lmt_insert_state.inserts[index].inbetween) {
787 distance = lmt_insert_state.inserts[index].inbetween;
788 } else {
789 distance = lmt_get_insert_distance(index, 2);
790 lmt_insert_state.inserts[index].inbetween = distance;
791 }
792 set_bit(bits,index);
793 }
794 if (distance) {
795 amount += glue_amount(distance);
796 if (stretch) {
797 *stretch += glue_stretch(distance);
798 }
799 if (shrink) {
800 *shrink += glue_shrink(distance);
801 }
802 }
803 }
804 c = node_next(c);
805 }
806 return amount;
807}
808 |