]> code.delx.au - gnu-emacs/blob - test/manual/etags/c-src/abbrev.c
Merge from origin/emacs-25
[gnu-emacs] / test / manual / etags / c-src / abbrev.c
1 /* Primitives for word-abbrev mode.
2 Copyright (C) 1985-1986, 1993, 1996, 1998, 2016 Free Software
3 Foundation, Inc.
4
5 This file is part of GNU Emacs.
6
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22
23 #include <config.h>
24 #include <stdio.h>
25 #include "lisp.h"
26 #include "commands.h"
27 #include "buffer.h"
28 #include "window.h"
29 #include "charset.h"
30 #include "syntax.h"
31
32 /* An abbrev table is an obarray.
33 Each defined abbrev is represented by a symbol in that obarray
34 whose print name is the abbreviation.
35 The symbol's value is a string which is the expansion.
36 If its function definition is non-nil, it is called
37 after the expansion is done.
38 The plist slot of the abbrev symbol is its usage count. */
39
40 /* List of all abbrev-table name symbols:
41 symbols whose values are abbrev tables. */
42
43 Lisp_Object Vabbrev_table_name_list;
44
45 /* The table of global abbrevs. These are in effect
46 in any buffer in which abbrev mode is turned on. */
47
48 Lisp_Object Vglobal_abbrev_table;
49
50 /* The local abbrev table used by default (in Fundamental Mode buffers) */
51
52 Lisp_Object Vfundamental_mode_abbrev_table;
53
54 /* Set nonzero when an abbrev definition is changed */
55
56 int abbrevs_changed;
57
58 int abbrev_all_caps;
59
60 /* Non-nil => use this location as the start of abbrev to expand
61 (rather than taking the word before point as the abbrev) */
62
63 Lisp_Object Vabbrev_start_location;
64
65 /* Buffer that Vabbrev_start_location applies to */
66 Lisp_Object Vabbrev_start_location_buffer;
67
68 /* The symbol representing the abbrev most recently expanded */
69
70 Lisp_Object Vlast_abbrev;
71
72 /* A string for the actual text of the abbrev most recently expanded.
73 This has more info than Vlast_abbrev since case is significant. */
74
75 Lisp_Object Vlast_abbrev_text;
76
77 /* Character address of start of last abbrev expanded */
78
79 int last_abbrev_point;
80
81 /* Hook to run before expanding any abbrev. */
82
83 Lisp_Object Vpre_abbrev_expand_hook, Qpre_abbrev_expand_hook;
84 \f
85 DEFUN ("make-abbrev-table", Fmake_abbrev_table, Smake_abbrev_table, 0, 0, 0,
86 "Create a new, empty abbrev table object.")
87 ()
88 {
89 return Fmake_vector (make_number (59), make_number (0));
90 }
91
92 DEFUN ("clear-abbrev-table", Fclear_abbrev_table, Sclear_abbrev_table, 1, 1, 0,
93 "Undefine all abbrevs in abbrev table TABLE, leaving it empty.")
94 (table)
95 Lisp_Object table;
96 {
97 int i, size;
98
99 CHECK_VECTOR (table, 0);
100 size = XVECTOR (table)->size;
101 abbrevs_changed = 1;
102 for (i = 0; i < size; i++)
103 XVECTOR (table)->contents[i] = make_number (0);
104 return Qnil;
105 }
106 \f
107 DEFUN ("define-abbrev", Fdefine_abbrev, Sdefine_abbrev, 3, 5, 0,
108 "Define an abbrev in TABLE named NAME, to expand to EXPANSION and call HOOK.\n\
109 NAME must be a string.\n\
110 EXPANSION should usually be a string.\n\
111 To undefine an abbrev, define it with EXPANSION = nil.\n\
112 If HOOK is non-nil, it should be a function of no arguments;\n\
113 it is called after EXPANSION is inserted.\n\
114 If EXPANSION is not a string, the abbrev is a special one,\n\
115 which does not expand in the usual way but only runs HOOK.\n\
116 COUNT, if specified, initializes the abbrev's usage-count\n\
117 which is incremented each time the abbrev is used.")
118 (table, name, expansion, hook, count)
119 Lisp_Object table, name, expansion, hook, count;
120 {
121 Lisp_Object sym, oexp, ohook, tem;
122 CHECK_VECTOR (table, 0);
123 CHECK_STRING (name, 1);
124
125 if (NILP (count))
126 count = make_number (0);
127 else
128 CHECK_NUMBER (count, 0);
129
130 sym = Fintern (name, table);
131
132 oexp = XSYMBOL (sym)->value;
133 ohook = XSYMBOL (sym)->function;
134 if (!((EQ (oexp, expansion)
135 || (STRINGP (oexp) && STRINGP (expansion)
136 && (tem = Fstring_equal (oexp, expansion), !NILP (tem))))
137 &&
138 (EQ (ohook, hook)
139 || (tem = Fequal (ohook, hook), !NILP (tem)))))
140 abbrevs_changed = 1;
141
142 Fset (sym, expansion);
143 Ffset (sym, hook);
144 Fsetplist (sym, count);
145
146 return name;
147 }
148
149 DEFUN ("define-global-abbrev", Fdefine_global_abbrev, Sdefine_global_abbrev, 2, 2,
150 "sDefine global abbrev: \nsExpansion for %s: ",
151 "Define ABBREV as a global abbreviation for EXPANSION.")
152 (abbrev, expansion)
153 Lisp_Object abbrev, expansion;
154 {
155 Fdefine_abbrev (Vglobal_abbrev_table, Fdowncase (abbrev),
156 expansion, Qnil, make_number (0));
157 return abbrev;
158 }
159
160 DEFUN ("define-mode-abbrev", Fdefine_mode_abbrev, Sdefine_mode_abbrev, 2, 2,
161 "sDefine mode abbrev: \nsExpansion for %s: ",
162 "Define ABBREV as a mode-specific abbreviation for EXPANSION.")
163 (abbrev, expansion)
164 Lisp_Object abbrev, expansion;
165 {
166 if (NILP (current_buffer->abbrev_table))
167 error ("Major mode has no abbrev table");
168
169 Fdefine_abbrev (current_buffer->abbrev_table, Fdowncase (abbrev),
170 expansion, Qnil, make_number (0));
171 return abbrev;
172 }
173
174 DEFUN ("abbrev-symbol", Fabbrev_symbol, Sabbrev_symbol, 1, 2, 0,
175 "Return the symbol representing abbrev named ABBREV.\n\
176 This symbol's name is ABBREV, but it is not the canonical symbol of that name;\n\
177 it is interned in an abbrev-table rather than the normal obarray.\n\
178 The value is nil if that abbrev is not defined.\n\
179 Optional second arg TABLE is abbrev table to look it up in.\n\
180 The default is to try buffer's mode-specific abbrev table, then global table.")
181 (abbrev, table)
182 Lisp_Object abbrev, table;
183 {
184 Lisp_Object sym;
185 CHECK_STRING (abbrev, 0);
186 if (!NILP (table))
187 sym = Fintern_soft (abbrev, table);
188 else
189 {
190 sym = Qnil;
191 if (!NILP (current_buffer->abbrev_table))
192 sym = Fintern_soft (abbrev, current_buffer->abbrev_table);
193 if (NILP (XSYMBOL (sym)->value))
194 sym = Qnil;
195 if (NILP (sym))
196 sym = Fintern_soft (abbrev, Vglobal_abbrev_table);
197 }
198 if (NILP (XSYMBOL (sym)->value)) return Qnil;
199 return sym;
200 }
201
202 DEFUN ("abbrev-expansion", Fabbrev_expansion, Sabbrev_expansion, 1, 2, 0,
203 "Return the string that ABBREV expands into in the current buffer.\n\
204 Optionally specify an abbrev table as second arg;\n\
205 then ABBREV is looked up in that table only.")
206 (abbrev, table)
207 Lisp_Object abbrev, table;
208 {
209 Lisp_Object sym;
210 sym = Fabbrev_symbol (abbrev, table);
211 if (NILP (sym)) return sym;
212 return Fsymbol_value (sym);
213 }
214 \f
215 /* Expand the word before point, if it is an abbrev.
216 Returns 1 if an expansion is done. */
217
218 DEFUN ("expand-abbrev", Fexpand_abbrev, Sexpand_abbrev, 0, 0, "",
219 "Expand the abbrev before point, if there is an abbrev there.\n\
220 Effective when explicitly called even when `abbrev-mode' is nil.\n\
221 Returns the abbrev symbol, if expansion took place.")
222 ()
223 {
224 register char *buffer, *p;
225 int wordstart, wordend;
226 register int wordstart_byte, wordend_byte, idx;
227 int whitecnt;
228 int uccount = 0, lccount = 0;
229 register Lisp_Object sym;
230 Lisp_Object expansion, hook, tem;
231 Lisp_Object value;
232
233 value = Qnil;
234
235 if (!NILP (Vrun_hooks))
236 call1 (Vrun_hooks, Qpre_abbrev_expand_hook);
237
238 wordstart = 0;
239 if (!(BUFFERP (Vabbrev_start_location_buffer)
240 && XBUFFER (Vabbrev_start_location_buffer) == current_buffer))
241 Vabbrev_start_location = Qnil;
242 if (!NILP (Vabbrev_start_location))
243 {
244 tem = Vabbrev_start_location;
245 CHECK_NUMBER_COERCE_MARKER (tem, 0);
246 wordstart = XINT (tem);
247 Vabbrev_start_location = Qnil;
248 if (wordstart < BEGV || wordstart > ZV)
249 wordstart = 0;
250 if (wordstart && wordstart != ZV)
251 {
252 wordstart_byte = CHAR_TO_BYTE (wordstart);
253 if (FETCH_BYTE (wordstart_byte) == '-')
254 del_range (wordstart, wordstart + 1);
255 }
256 }
257 if (!wordstart)
258 wordstart = scan_words (PT, -1);
259
260 if (!wordstart)
261 return value;
262
263 wordstart_byte = CHAR_TO_BYTE (wordstart);
264 wordend = scan_words (wordstart, 1);
265 if (!wordend)
266 return value;
267
268 if (wordend > PT)
269 wordend = PT;
270
271 wordend_byte = CHAR_TO_BYTE (wordend);
272 whitecnt = PT - wordend;
273 if (wordend <= wordstart)
274 return value;
275
276 p = buffer = (char *) alloca (wordend_byte - wordstart_byte);
277
278 for (idx = wordstart_byte; idx < wordend_byte; idx++)
279 {
280 /* ??? This loop needs to go by characters! */
281 register int c = FETCH_BYTE (idx);
282 if (UPPERCASEP (c))
283 c = DOWNCASE (c), uccount++;
284 else if (! NOCASEP (c))
285 lccount++;
286 *p++ = c;
287 }
288
289 if (VECTORP (current_buffer->abbrev_table))
290 sym = oblookup (current_buffer->abbrev_table, buffer,
291 wordend - wordstart, wordend_byte - wordstart_byte);
292 else
293 XSETFASTINT (sym, 0);
294 if (INTEGERP (sym) || NILP (XSYMBOL (sym)->value))
295 sym = oblookup (Vglobal_abbrev_table, buffer,
296 wordend - wordstart, wordend_byte - wordstart_byte);
297 if (INTEGERP (sym) || NILP (XSYMBOL (sym)->value))
298 return value;
299
300 if (INTERACTIVE && !EQ (minibuf_window, selected_window))
301 {
302 /* Add an undo boundary, in case we are doing this for
303 a self-inserting command which has avoided making one so far. */
304 SET_PT (wordend);
305 Fundo_boundary ();
306 }
307
308 Vlast_abbrev_text
309 = Fbuffer_substring (make_number (wordstart), make_number (wordend));
310
311 /* Now sym is the abbrev symbol. */
312 Vlast_abbrev = sym;
313 value = sym;
314 last_abbrev_point = wordstart;
315
316 if (INTEGERP (XSYMBOL (sym)->plist))
317 XSETINT (XSYMBOL (sym)->plist,
318 XINT (XSYMBOL (sym)->plist) + 1); /* Increment use count */
319
320 /* If this abbrev has an expansion, delete the abbrev
321 and insert the expansion. */
322 expansion = XSYMBOL (sym)->value;
323 if (STRINGP (expansion))
324 {
325 SET_PT (wordstart);
326
327 del_range_both (wordstart, wordstart_byte, wordend, wordend_byte, 1);
328
329 insert_from_string (expansion, 0, 0, XSTRING (expansion)->size,
330 STRING_BYTES (XSTRING (expansion)), 1);
331 SET_PT (PT + whitecnt);
332
333 if (uccount && !lccount)
334 {
335 /* Abbrev was all caps */
336 /* If expansion is multiple words, normally capitalize each word */
337 /* This used to be if (!... && ... >= ...) Fcapitalize; else Fupcase
338 but Megatest 68000 compiler can't handle that */
339 if (!abbrev_all_caps)
340 if (scan_words (PT, -1) > scan_words (wordstart, 1))
341 {
342 Fupcase_initials_region (make_number (wordstart),
343 make_number (PT));
344 goto caped;
345 }
346 /* If expansion is one word, or if user says so, upcase it all. */
347 Fupcase_region (make_number (wordstart), make_number (PT));
348 caped: ;
349 }
350 else if (uccount)
351 {
352 /* Abbrev included some caps. Cap first initial of expansion */
353 int pos = wordstart_byte;
354
355 /* Find the initial. */
356 while (pos < PT_BYTE
357 && SYNTAX (*BUF_BYTE_ADDRESS (current_buffer, pos)) != Sword)
358 pos++;
359
360 /* Change just that. */
361 pos = BYTE_TO_CHAR (pos);
362 Fupcase_initials_region (make_number (pos), make_number (pos + 1));
363 }
364 }
365
366 hook = XSYMBOL (sym)->function;
367 if (!NILP (hook))
368 {
369 Lisp_Object expanded, prop;
370
371 /* If the abbrev has a hook function, run it. */
372 expanded = call0 (hook);
373
374 /* In addition, if the hook function is a symbol with a a
375 non-nil `no-self-insert' property, let the value it returned
376 specify whether we consider that an expansion took place. If
377 it returns nil, no expansion has been done. */
378
379 if (SYMBOLP (hook)
380 && NILP (expanded)
381 && (prop = Fget (hook, intern ("no-self-insert")),
382 !NILP (prop)))
383 value = Qnil;
384 }
385
386 return value;
387 }
388
389 DEFUN ("unexpand-abbrev", Funexpand_abbrev, Sunexpand_abbrev, 0, 0, "",
390 "Undo the expansion of the last abbrev that expanded.\n\
391 This differs from ordinary undo in that other editing done since then\n\
392 is not undone.")
393 ()
394 {
395 int opoint = PT;
396 int adjust = 0;
397 if (last_abbrev_point < BEGV
398 || last_abbrev_point > ZV)
399 return Qnil;
400 SET_PT (last_abbrev_point);
401 if (STRINGP (Vlast_abbrev_text))
402 {
403 /* This isn't correct if Vlast_abbrev->function was used
404 to do the expansion */
405 Lisp_Object val;
406 int zv_before;
407
408 val = XSYMBOL (Vlast_abbrev)->value;
409 if (!STRINGP (val))
410 error ("value of abbrev-symbol must be a string");
411 zv_before = ZV;
412 del_range_byte (PT_BYTE, PT_BYTE + STRING_BYTES (XSTRING (val)), 1);
413 /* Don't inherit properties here; just copy from old contents. */
414 insert_from_string (Vlast_abbrev_text, 0, 0,
415 XSTRING (Vlast_abbrev_text)->size,
416 STRING_BYTES (XSTRING (Vlast_abbrev_text)), 0);
417 Vlast_abbrev_text = Qnil;
418 /* Total number of characters deleted. */
419 adjust = ZV - zv_before;
420 }
421 SET_PT (last_abbrev_point < opoint ? opoint + adjust : opoint);
422 return Qnil;
423 }
424 \f
425 static void
426 write_abbrev (sym, stream)
427 Lisp_Object sym, stream;
428 {
429 Lisp_Object name;
430 if (NILP (XSYMBOL (sym)->value))
431 return;
432 insert (" (", 5);
433 XSETSTRING (name, XSYMBOL (sym)->name);
434 Fprin1 (name, stream);
435 insert (" ", 1);
436 Fprin1 (XSYMBOL (sym)->value, stream);
437 insert (" ", 1);
438 Fprin1 (XSYMBOL (sym)->function, stream);
439 insert (" ", 1);
440 Fprin1 (XSYMBOL (sym)->plist, stream);
441 insert (")\n", 2);
442 }
443
444 static void
445 describe_abbrev (sym, stream)
446 Lisp_Object sym, stream;
447 {
448 Lisp_Object one;
449
450 if (NILP (XSYMBOL (sym)->value))
451 return;
452 one = make_number (1);
453 Fprin1 (Fsymbol_name (sym), stream);
454 Findent_to (make_number (15), one);
455 Fprin1 (XSYMBOL (sym)->plist, stream);
456 Findent_to (make_number (20), one);
457 Fprin1 (XSYMBOL (sym)->value, stream);
458 if (!NILP (XSYMBOL (sym)->function))
459 {
460 Findent_to (make_number (45), one);
461 Fprin1 (XSYMBOL (sym)->function, stream);
462 }
463 Fterpri (stream);
464 }
465
466 DEFUN ("insert-abbrev-table-description", Finsert_abbrev_table_description,
467 Sinsert_abbrev_table_description, 1, 2, 0,
468 "Insert before point a full description of abbrev table named NAME.\n\
469 NAME is a symbol whose value is an abbrev table.\n\
470 If optional 2nd arg READABLE is non-nil, a human-readable description\n\
471 is inserted. Otherwise the description is an expression,\n\
472 a call to `define-abbrev-table', which would\n\
473 define the abbrev table NAME exactly as it is currently defined.")
474 (name, readable)
475 Lisp_Object name, readable;
476 {
477 Lisp_Object table;
478 Lisp_Object stream;
479
480 CHECK_SYMBOL (name, 0);
481 table = Fsymbol_value (name);
482 CHECK_VECTOR (table, 0);
483
484 XSETBUFFER (stream, current_buffer);
485
486 if (!NILP (readable))
487 {
488 insert_string ("(");
489 Fprin1 (name, stream);
490 insert_string (")\n\n");
491 map_obarray (table, describe_abbrev, stream);
492 insert_string ("\n\n");
493 }
494 else
495 {
496 insert_string ("(define-abbrev-table '");
497 Fprin1 (name, stream);
498 insert_string (" '(\n");
499 map_obarray (table, write_abbrev, stream);
500 insert_string (" ))\n\n");
501 }
502
503 return Qnil;
504 }
505 \f
506 DEFUN ("define-abbrev-table", Fdefine_abbrev_table, Sdefine_abbrev_table,
507 2, 2, 0,
508 "Define TABLENAME (a symbol) as an abbrev table name.\n\
509 Define abbrevs in it according to DEFINITIONS, which is a list of elements\n\
510 of the form (ABBREVNAME EXPANSION HOOK USECOUNT).")
511 (tablename, definitions)
512 Lisp_Object tablename, definitions;
513 {
514 Lisp_Object name, exp, hook, count;
515 Lisp_Object table, elt;
516
517 CHECK_SYMBOL (tablename, 0);
518 table = Fboundp (tablename);
519 if (NILP (table) || (table = Fsymbol_value (tablename), NILP (table)))
520 {
521 table = Fmake_abbrev_table ();
522 Fset (tablename, table);
523 Vabbrev_table_name_list = Fcons (tablename, Vabbrev_table_name_list);
524 }
525 CHECK_VECTOR (table, 0);
526
527 for (; !NILP (definitions); definitions = Fcdr (definitions))
528 {
529 elt = Fcar (definitions);
530 name = Fcar (elt); elt = Fcdr (elt);
531 exp = Fcar (elt); elt = Fcdr (elt);
532 hook = Fcar (elt); elt = Fcdr (elt);
533 count = Fcar (elt);
534 Fdefine_abbrev (table, name, exp, hook, count);
535 }
536 return Qnil;
537 }
538 \f
539 void
540 syms_of_abbrev ()
541 {
542 DEFVAR_LISP ("abbrev-table-name-list", &Vabbrev_table_name_list,
543 "List of symbols whose values are abbrev tables.");
544 Vabbrev_table_name_list = Fcons (intern ("fundamental-mode-abbrev-table"),
545 Fcons (intern ("global-abbrev-table"),
546 Qnil));
547
548 DEFVAR_LISP ("global-abbrev-table", &Vglobal_abbrev_table,
549 "The abbrev table whose abbrevs affect all buffers.\n\
550 Each buffer may also have a local abbrev table.\n\
551 If it does, the local table overrides the global one\n\
552 for any particular abbrev defined in both.");
553 Vglobal_abbrev_table = Fmake_abbrev_table ();
554
555 DEFVAR_LISP ("fundamental-mode-abbrev-table", &Vfundamental_mode_abbrev_table,
556 "The abbrev table of mode-specific abbrevs for Fundamental Mode.");
557 Vfundamental_mode_abbrev_table = Fmake_abbrev_table ();
558 current_buffer->abbrev_table = Vfundamental_mode_abbrev_table;
559 buffer_defaults.abbrev_table = Vfundamental_mode_abbrev_table;
560
561 DEFVAR_LISP ("last-abbrev", &Vlast_abbrev,
562 "The abbrev-symbol of the last abbrev expanded. See `abbrev-symbol'.");
563
564 DEFVAR_LISP ("last-abbrev-text", &Vlast_abbrev_text,
565 "The exact text of the last abbrev expanded.\n\
566 nil if the abbrev has already been unexpanded.");
567
568 DEFVAR_INT ("last-abbrev-location", &last_abbrev_point,
569 "The location of the start of the last abbrev expanded.");
570
571 Vlast_abbrev = Qnil;
572 Vlast_abbrev_text = Qnil;
573 last_abbrev_point = 0;
574
575 DEFVAR_LISP ("abbrev-start-location", &Vabbrev_start_location,
576 "Buffer position for `expand-abbrev' to use as the start of the abbrev.\n\
577 nil means use the word before point as the abbrev.\n\
578 Calling `expand-abbrev' sets this to nil.");
579 Vabbrev_start_location = Qnil;
580
581 DEFVAR_LISP ("abbrev-start-location-buffer", &Vabbrev_start_location_buffer,
582 "Buffer that `abbrev-start-location' has been set for.\n\
583 Trying to expand an abbrev in any other buffer clears `abbrev-start-location'.");
584 Vabbrev_start_location_buffer = Qnil;
585
586 DEFVAR_PER_BUFFER ("local-abbrev-table", &current_buffer->abbrev_table, Qnil,
587 "Local (mode-specific) abbrev table of current buffer.");
588
589 DEFVAR_BOOL ("abbrevs-changed", &abbrevs_changed,
590 "Set non-nil by defining or altering any word abbrevs.\n\
591 This causes `save-some-buffers' to offer to save the abbrevs.");
592 abbrevs_changed = 0;
593
594 DEFVAR_BOOL ("abbrev-all-caps", &abbrev_all_caps,
595 "*Set non-nil means expand multi-word abbrevs all caps if abbrev was so.");
596 abbrev_all_caps = 0;
597
598 DEFVAR_LISP ("pre-abbrev-expand-hook", &Vpre_abbrev_expand_hook,
599 "Function or functions to be called before abbrev expansion is done.\n\
600 This is the first thing that `expand-abbrev' does, and so this may change\n\
601 the current abbrev table before abbrev lookup happens.");
602 Vpre_abbrev_expand_hook = Qnil;
603 Qpre_abbrev_expand_hook = intern ("pre-abbrev-expand-hook");
604 staticpro (&Qpre_abbrev_expand_hook);
605
606 defsubr (&Smake_abbrev_table);
607 defsubr (&Sclear_abbrev_table);
608 defsubr (&Sdefine_abbrev);
609 defsubr (&Sdefine_global_abbrev);
610 defsubr (&Sdefine_mode_abbrev);
611 defsubr (&Sabbrev_expansion);
612 defsubr (&Sabbrev_symbol);
613 defsubr (&Sexpand_abbrev);
614 defsubr (&Sunexpand_abbrev);
615 defsubr (&Sinsert_abbrev_table_description);
616 defsubr (&Sdefine_abbrev_table);
617 }