commit b5586b1

0uppy  ·  2026-09-08 19:42:06 +0000 UTC
parent c6d7e65
cot - started remaking cot (aiming to make it a concatenated lang) and remade the interpreter for cot
9 files changed,  +215, -400
+0, -0
+2, -0
1@@ -0,0 +1,2 @@
2+print "test test this is a test" print
3+print "does cot render text okay again uhhh" print
+0, -16
 1@@ -1,16 +0,0 @@
 2-color blabla
 3-print "hallo this is" /n
 4-color whie
 5-print "a showcase cot file" /n
 6-color lav
 7-print "to show YOU" /n
 8-color wink
 9-print "cotton's slightly new" /n
10-color sink
11-print "cottolette,..," /n
12-color wist
13-print "i hope yuo guys liek it" /n
14-color yebow
15-print "thats it" /n
16-color geen
17-print "geen" /n
+0, -9
 1@@ -1,9 +0,0 @@
 2-print "ABCDEFGHIJKL"
 3-print "MNOPQRSTUVWX"
 4-print "YZ"
 5-print "abcdefghijkl"
 6-print "mnopqrstuvwx"
 7-print "yz"
 8-
 9-print "1234567890"
10-print "! ? ; : ."
+0, -5
1@@ -1,5 +0,0 @@
2-print "HELLO FROM COT :D"
3-wait 1
4-print "THIS IS A SHOWCASE COT FILE"
5-wait 1
6-print "WORDS WORDS WORDS"
+1, -1
1@@ -1,5 +1,5 @@
2 project('cotton', 'c',
3-  version : '0.2',
4+  version : '0.3',
5   default_options : ['c_std=c99', 'warning_level=2'])
6 
7 sdl2 = dependency('sdl2')
+2, -24
 1@@ -11,29 +11,7 @@ void cotton_init
 2 
 3     srand((unsigned int)time(NULL));
 4 
 5-    c->c_cottolette = COTTOLETTE[1];
 6-}
 7-
 8-void cotton_store_var
 9-(Cotton *cotton, const char *name, const char *value)
10-{
11-    for (int i = 0; i < cotton->var_count; i++) {
12-        if (strcmp(cotton->vars[i].name, name) == 0) {
13-            strncpy(cotton->vars[i].value, value, VAR_VAL_LEN - 1);
14-            cotton->vars[i].value[VAR_VAL_LEN - 1] = '\0';
15-            return;
16-        }
17-    }
18+	c->stack_p = 0;
19 
20-    if (cotton->var_count < VARS) { 
21-        strncpy(cotton->vars[cotton->var_count].name, name, VAR_NAME_LEN - 1);
22-        cotton->vars[cotton->var_count].name[VAR_NAME_LEN - 1] = '\0';
23-
24-        strncpy(cotton->vars[cotton->var_count].value, value, VAR_VAL_LEN - 1);
25-        cotton->vars[cotton->var_count].value[VAR_VAL_LEN - 1] = '\0';
26-
27-        cotton->var_count++;
28-    } else {
29-        fprintf(stderr, "cotton ran out of variable slots :( - max ammount is %d\n", VARS);
30-    }
31+    c->c_cottolette = COTTOLETTE[1];
32 }
+4, -1
 1@@ -46,7 +46,10 @@ typedef struct
 2                            // alot to type and im lazyyyyyyy bwaaaaaa
 3 
 4     CotVar vars[VARS];
 5-    int var_count;
 6+	int var_count;
 7+
 8+	int stack[32];
 9+	int stack_p;
10 
11 } Cotton;
12 
+206, -344
  1@@ -1,4 +1,4 @@
  2-// i got to eventually clean up this file a bit i feel like its very janky but i suppose i can worry about that later
  3+// i got to eventually clean up this file a bit i feel like its very janky but i suppose i can worry about that later - future dani here, it seems you ended up just remaking the entire file bc you thought remaking cot into a concatenated language was cooler, good job dani - future future dani here, thank you dani :D
  4 
  5 #include "interpreter.h"
  6 #include "cottonwindow.h"
  7@@ -7,405 +7,267 @@
  8 #include <stdio.h>
  9 #include <stdlib.h>
 10 #include <string.h>
 11-#include <unistd.h>
 12+#include <ctype.h>
 13 
 14-// maximum length of a .cot file line
 15 #define MAX_LINE 256
 16 
 17-// da string AND variable stuff
 18-
 19-static void 
 20-strip_newline(char *s) 
 21+// da stack 
 22+static void push
 23+(Cotton *c, int v)
 24 {
 25-     s[strcspn(s, "\r\n")] = 0; 
 26+    if (c->stack_p >= 64) {
 27+        fprintf(stderr, "cot: there has been a stack overflow :< (like the website badumptsss)\n");
 28+        return;
 29+    }
 30+
 31+    c->stack[c->stack_p++] = v;
 32 }
 33 
 34-static char 
 35-*get_arg (char *line)
 36+static int pop
 37+(Cotton *c)
 38 {
 39-    char *space = strchr(line, ' ');
 40-
 41-    if (space != NULL) {
 42-        return space + 1;
 43+    if (c->stack_p <= 0) {
 44+        fprintf(stderr, "cot: there has been a stack underflow :<\n");
 45+        return 0;
 46     }
 47 
 48-    else {
 49-        return NULL;
 50-    }
 51+    return c->stack[--c->stack_p];
 52 }
 53 
 54-static char 
 55-*strip_quotes(char *s)
 56+// da variable stuff
 57+static int find_var
 58+(Cotton *c, const char *name)
 59 {
 60-    if (s[0] == '"') {
 61-        char *end = strrchr(s, '"');
 62-
 63-        if (end == NULL) {
 64-            fprintf(stderr, "cot syntax error : looks like you forgot a quote at the end xP\n");
 65-            return s;
 66-        }
 67-
 68-        *end = '\0';
 69-        return s + 1;
 70+    for (int i = 0; i < c->var_count; i++) {
 71+        if (strcmp(c->vars[i].name, name) == 0) return i;
 72     }
 73 
 74-    return s;
 75+    return -1;
 76 }
 77 
 78-static const char
 79-*get_var_value(Cotton *cotton, const char *name)
 80+static void add_var
 81+(Cotton *c, const char *name)
 82 {
 83-    for (int i = 0; i < cotton->var_count; i++) {
 84-        if (strcmp(cotton->vars[i].name, name) == 0) {
 85-            return cotton->vars[i].value;
 86-        }
 87+    if (c->var_count >= VARS) {
 88+        fprintf(stderr, "cot: too many variables\n");
 89+        return;
 90     }
 91-    return NULL;
 92-}
 93 
 94-// da graphics stuff
 95+    strncpy(c->vars[c->var_count].name, name, VAR_NAME_LEN - 1);
 96+    c->vars[c->var_count].name[VAR_NAME_LEN - 1] = '\0';
 97+    strcpy(c->vars[c->var_count].value, "0");
 98+    c->var_count++;
 99+}
100 
101-static void 
102-draw_pixel (Cotton *cotton, int x, int y)
103+// da graphics
104+static void draw_pixel_c
105+(Cotton *c, int x, int y)
106 {
107-    cotton->video[y * VIDEO_WIDTH + x] = cotton->c_cottolette;
108+   	if (x < 0 || x >= VIDEO_WIDTH || y < 0 || y >= VIDEO_HEIGHT) return;
109+    c->video[y * VIDEO_WIDTH + x] = c->c_cottolette;
110 }
111 
112-static void 
113-draw_char (Cotton *cotton, char c, int x, int y)
114+static void draw_char_c
115+(Cotton *c, char ch, int x, int y)
116 {
117     for (int row = 0; row < FONT_HEIGHT; row++) {
118-        uint8_t bits = EIKI_FONT[(uint8_t)c][row];
119+        uint8_t bits = EIKI_FONT[(uint8_t)ch][row];
120 
121         for (int col = 0; col < FONT_WIDTH; col++) {
122-
123             if (bits & (1 << col)) {
124-                draw_pixel(cotton, x + col, y + row);
125+                draw_pixel_c(c, x + col, y + row);
126             }
127         }
128     }
129 }
130 
131-// da commands
132-
133-static void 
134-cmd_print(Cotton *cotton, CottonWindow *cw, char *arg)
135+// those who interpretate skull emoji skull emoji nahhhh get outttttttttt skull emoji door emoji
136+void cotton_interpret
137+(Cotton *c, CottonWindow *cw, FILE *file)
138 {
139-    if (!arg)
140-        return;
141-
142-    int nl = 0;
143-    char *nl_str = strstr(arg, " /n");
144-
145-    if (nl_str != NULL) {
146-        nl = 1;
147-        *nl_str = '\0';
148-    }
149-
150-    char *text = strip_quotes(arg);
151-
152-    const char *value = get_var_value(cotton, text);
153-    if (value != NULL) {
154-        text = (char *)value;
155-    }
156-
157-    if (nl) {
158-        printf("%s\n", text);
159-    } else {
160-        printf("%s", text);
161-        fflush(stdout);
162-    }
163-
164-    for (int i = 0; text[i] != '\0'; i++) {
165-        if (text[i] == '\n') {
166-            cotton->cursor_x = 0;
167-            cotton->cursor_y += FONT_HEIGHT + 4;
168-            continue;
169+    char line[MAX_LINE];
170+    if (!fgets(line, sizeof(line), file)) return;
171+    
172+    line[strcspn(line, "\r\n")] = 0;
173+    if (line[0] == '\0' || (line[0] == '/' && line[1] == '/')) return;
174+    
175+    char *tok = strtok(line, " ");
176+    
177+    while (tok) {
178+
179+        int is_a_num = 1;
180+        for (int i = 0; tok[i]; i++) {
181+            if (!isdigit(tok[i]) && !(i == 0 && tok[i] == '-')) {
182+                is_a_num = 0;
183+                break;
184+            }
185         }
186-
187-        draw_char(cotton, text[i], cotton->cursor_x, cotton->cursor_y);
188-        cotton->cursor_x += FONT_WIDTH + 2;
189-
190-        if (cotton->cursor_x + FONT_WIDTH + 2 >= VIDEO_WIDTH) {
191-            cotton->cursor_x = 0;
192-            cotton->cursor_y += FONT_HEIGHT + 4;
193+        
194+        if (is_a_num) {
195+            push(c, atoi(tok));
196         }
197-    }
198-
199-    if (nl) {
200-        cotton->cursor_x = 0;
201-        cotton->cursor_y += FONT_HEIGHT + 4;
202-    }
203-
204-    cottonwindow_update(cw, cotton->video, sizeof(cotton->video[0]) * VIDEO_WIDTH);
205-}
206-
207-static void 
208-cmd_pixel(Cotton *cotton, CottonWindow *cw, char *arg)
209-{
210-    int x, y;
211-
212-    if (!arg || sscanf(arg, "%d %d", &x, &y) != 2) {
213-        fprintf(stderr, "cot syntax error: usage for pixel is 'pixel <x> <y>' :P\n");
214-        return;
215-    }
216 
217-    if (x < 0 || x >= VIDEO_WIDTH || y < 0 || y >= VIDEO_HEIGHT) {
218-        fprintf(stderr, "cot syntax error: pixel (%d, %d) is out of bounds :<\n", x, y);
219-        return;
220-    }
221-
222-    draw_pixel(cotton, x, y);
223-
224-    cottonwindow_update(cw, cotton->video, sizeof(cotton->video[0]) * VIDEO_WIDTH);
225-}
226-
227-static void 
228-cmd_var(Cotton *cotton, char *arg)
229-{
230-    if (!arg)
231-        return;
232-
233-    char *space = strchr(arg, ' ');
234-    if (!space) {
235-        fprintf(stderr, "cot syntax error: you forgor to put a value for your variable xP\n");
236-        return;
237-    }
238-
239-    *space = '\0';
240-    char *name = arg;
241-    char *value = space + 1;
242-
243-    cotton_store_var(cotton, name, value);
244-}
245-
246-static void 
247-cmd_clear(Cotton *cotton, CottonWindow *cw)
248-{
249-    for (int i = 0; i < VIDEO_WIDTH * VIDEO_HEIGHT; i++) {
250-        cotton->video[i] = 0;
251-    }
252-
253-    cotton->cursor_x = 0;
254-    cotton->cursor_y = 0;
255-
256-    cottonwindow_update(cw, cotton->video, sizeof(cotton->video[0]) * VIDEO_WIDTH);
257-}
258-
259-static void
260-cmd_color(Cotton *cotton, char *arg)
261-{
262-    if (!arg)
263-        return;
264-
265-    if (strcmp(arg, "blabla") == 0)
266-        cotton->c_cottolette = COTTOLETTE[0];
267-
268-    else if (strcmp(arg, "whie") == 0)
269-        cotton->c_cottolette = COTTOLETTE[1];
270-
271-    else if (strcmp(arg, "lav") == 0)
272-        cotton->c_cottolette = COTTOLETTE[2];
273-
274-    else if (strcmp(arg, "wink") == 0)
275-        cotton->c_cottolette = COTTOLETTE[3];
276-
277-    else if (strcmp(arg, "sink") == 0)
278-        cotton->c_cottolette = COTTOLETTE[4];
279-
280-    else if (strcmp(arg, "wist") == 0)
281-        cotton->c_cottolette = COTTOLETTE[5];
282-
283-    else if (strcmp(arg, "yebow") == 0)
284-        cotton->c_cottolette = COTTOLETTE[6];
285-
286-    else if (strcmp(arg, "geen") == 0)
287-        cotton->c_cottolette = COTTOLETTE[7];
288-
289-    else
290-        fprintf(stderr, "cot syntax error: cotton doesn't know the color \"%s\" sorry,, :(\n", arg);
291-}
292-
293-static void 
294-cmd_wait(Cotton *cotton, char *arg)
295-{
296-    if (!arg)
297-        return;
298+		// those who do math..., math from the epic video gaem baldi's basics in education and learning,., you guys should play it its a good game i like baldi,. send me an email telling me your guys' PR on endless mode 
299+        else if (strcmp(tok, "+") == 0) {
300+            int b = pop(c), a = pop(c);
301+            push(c, a + b);
302+        }
303 
304-    int seconds = atoi(arg);
305+        else if (strcmp(tok, "-") == 0) {
306+            int b = pop(c), a = pop(c);
307+            push(c, a - b);
308+        }
309 
310-    cotton->ticktock = SDL_GetTicks() + (seconds * 1000);
311-}
312+        else if (strcmp(tok, "*") == 0) {
313+            int b = pop(c), a = pop(c);
314+            push(c, a * b);
315+        }
316 
317-static void 
318-cmd_input(Cotton *cotton, char *arg)
319-{
320-    if (!arg) {
321-        fprintf(stderr, "cotton syntax error: input needs a variable name xP\n");
322-        return;
323-    }
324+        else if (strcmp(tok, "/") == 0) {
325+            int b = pop(c), a = pop(c);
326+            push(c, a / b);
327+        }
328 
329-    char buffer[VAR_VAL_LEN];
330+		// while forth does use ! and @, im quirky and #notlikeothergirls so im changing ! to -> bc i think it makes more sense :P
331+        else if (strcmp(tok, "->") == 0) {
332 
333-    // kind of a quick and dirty way of implementing input, i know, but, i cant be arsed to get myself into a potential rabbit hole with SDL so for now i  will leave this to be this way,, sorry,,
334-    if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
335-        buffer[strcspn(buffer, "\r\n")] = '\0';
336+            int slot = pop(c);
337+			int num = pop(c);
338+			
339+			if (slot >= 0 && slot < c->var_count) {
340+                char buf[VAR_VAL_LEN];
341+                sprintf(buf, "%d", num);
342+                strncpy(c->vars[slot].value, buf, VAR_VAL_LEN - 1);
343+			} 	
344 
345-        cotton_store_var(cotton, arg, buffer);
346-    }
347-}
348+			else {
349+                fprintf(stderr, "cot: tried to store somewhere that don't exist.,. its in the void now.., :<\n");
350+            }
351+        }
352 
353-static void 
354-cmd_kill(void)
355-{
356-    printf("[cotton stopped]\n");
357-    exit(0);
358-}
359+        else if (strcmp(tok, "@") == 0) {
360+            int slot = pop(c);
361 
362-static void 
363-cmd_math(Cotton *cotton, char *arg, char op)
364-{
365-    char var_name[64];
366-    char value[64];
367+        if (slot >= 0 && slot < c->var_count) {
368+                push(c, atoi(c->vars[slot].value));
369+            } 
370 
371-    if (!arg || sscanf(arg, "%63s %63s", var_name, value) != 2) {
372-        fprintf(stderr, "cot syntax error: usage is '<add, sub, mult, div> <variable> <number OR another variable>'\n");
373-        return;
374-    }
375+        else {
376+        	fprintf(stderr, "cot: tried to fetch from somewhere that don't exist,., :<\n");
377+       	}
378 
379-    int current = 0;
380-    int amount = 0;
381+        }
382 
383-    // thank you clang for coming in clutch and telling me to make this const i forgor (skull emoji)
384-    const char *var = get_var_value(cotton, var_name);
385-    if (var) {
386-        current = atoi(var);
387-    }
388+        else if (strcmp(tok, ".") == 0) {
389+            printf("%d", pop(c));
390+            fflush(stdout);
391+        }
392 
393-    // and this too, i love clang, clang is the best compiler evah !!!
394-    const char *other = get_var_value(cotton, value);
395-    if (other) {
396-        amount = atoi(other);
397-    } else {
398-        amount = atoi(value);
399-    }
400+        else if (strcmp(tok, "var") == 0) {
401+            tok = strtok(NULL, " ");
402+            if (tok) add_var(c, tok);
403+        }
404 
405-    switch (op) {
406-        case '+':
407-            current += amount;
408-            break;
409+        else if (strcmp(tok, "pixel") == 0) {
410+            int y = pop(c);
411+            int x = pop(c);
412+            draw_pixel_c(c, x, y);
413+            cottonwindow_update(cw, c->video, sizeof(c->video[0]) * VIDEO_WIDTH);
414+        }
415 
416-        case '-':
417-            current -= amount;
418-            break;
419+        else if (strcmp(tok, "color") == 0) {
420+            int slot = pop(c);
421+            if (slot >= 0 && slot < COTTOLETTE_SIZE)
422+                c->c_cottolette = COTTOLETTE[slot];
423+        }
424 
425-        case '*':
426-            current *= amount;
427-            break;
428+        else if (strcmp(tok, "clear") == 0) {
429+            for (int i = 0; i < VIDEO_WIDTH * VIDEO_HEIGHT; i++) 
430+                c->video[i] = 0;
431+            c->cursor_x = 0;
432+            c->cursor_y = 0;
433+            cottonwindow_update(cw, c->video, sizeof(c->video[0]) * VIDEO_WIDTH);
434+        }
435 
436-        case '/':        
437-            current /= amount;
438+		// the great wall of colors
439+        else if (strcmp(tok, "blabla") == 0) push(c, 0);
440+        else if (strcmp(tok, "whie") == 0) push(c, 1);
441+        else if (strcmp(tok, "lav") == 0) push(c, 2);
442+        else if (strcmp(tok, "wink") == 0) push(c, 3);
443+        else if (strcmp(tok, "sink") == 0) push(c, 4);
444+        else if (strcmp(tok, "wist") == 0) push(c, 5);
445+        else if (strcmp(tok, "yebow") == 0) push(c, 6);
446+        else if (strcmp(tok, "geen") == 0) push(c, 7);
447+
448+        else if (strcmp(tok, "print") == 0) {
449+            char *str = strtok(NULL, "");
450+            
451+            if (str) {
452+                while (*str == ' ') str++;
453+                
454+                int nl = 0;
455+                char *nl_at = strstr(str, " /n");
456+
457+            if (nl_at) {
458+                    *nl_at = '\0';
459+                    nl = 1;
460+                }
461+                
462+                if (str[0] == '"') {
463+                    str++;
464+                    char *end = strrchr(str, '"');
465+                    if (end) *end = '\0';
466+                }
467+                
468+                printf("%s", str);
469+                if (nl) printf("\n");
470+                fflush(stdout);
471+                
472+                for (int i = 0; str[i]; i++) {
473+                    if (str[i] == '\n') {
474+                        c->cursor_x = 0;
475+                        c->cursor_y += FONT_HEIGHT + 4;
476+                        continue;
477+                    }
478+
479+            		draw_char_c(c, str[i], c->cursor_x, c->cursor_y);
480+                    c->cursor_x += FONT_WIDTH + 2;
481+
482+                    if (c->cursor_x + FONT_WIDTH >= VIDEO_WIDTH) {
483+                        c->cursor_x = 0;
484+                        c->cursor_y += FONT_HEIGHT + 4;
485+                    }
486+                }
487+
488+                if (nl) {
489+                    c->cursor_x = 0;
490+                    c->cursor_y += FONT_HEIGHT + 4;
491+                }
492+
493+                cottonwindow_update(cw, c->video, sizeof(c->video[0]) * VIDEO_WIDTH);
494+            }
495             break;
496+        }
497+        
498+        else if (strcmp(tok, "wait") == 0) {
499+            c->ticktock = SDL_GetTicks() + pop(c);
500+        }
501 
502-        default:
503-            fprintf(stderr, "cot syntax error: cot doesn't know what operator this is :( \n");
504-            return;
505-    }
506-
507-    char buffer[32];
508-    sprintf(buffer, "%d", current);
509-
510-    cotton_store_var(cotton, var_name, buffer);
511-}
512-
513-static void 
514-cmd_unknown(const char *cmd)
515-{
516-    fprintf(stderr,
517-            "cot syntax error: cotton doesn't know what \"%s\" means, care to "
518-            "type that out again? :<\n",
519-            cmd);
520-}
521-
522-// da interpreter loop
523-
524-void 
525-cotton_interpret(Cotton *cotton, CottonWindow *cw, FILE *file)
526-{
527-    char line[MAX_LINE];
528-
529-    // this reads the file one line at a time until we get to da end of da file
530-    if (!fgets(line, sizeof(line), file))
531-        return;
532-
533-    strip_newline(line);
534-
535-// there used to be a joke about cot using # comments "like C" which was an inside joke but after this being pointed out because of genuine curiosity i decided to just change the comments in cot to //, more used to that anyway bwaa
536-        if (line[0] == '\0' || (line[0] == '/' && line[1] == '/')) // thank you for the fix emilia!! :D
537-        return;
538-
539-    char line_copy[MAX_LINE];
540-
541-    strncpy(line_copy, line, MAX_LINE - 1);
542-    line_copy[MAX_LINE - 1] = '\0';
543-
544-    char *cmd = strtok(line_copy, " ");
545-
546-    if (!cmd)
547-        return;
548-
549-    // RELEASE THE KRAKE- I MEAN, RELEASE THE GREAT WALL OF COMMANDS !!! could i format this better? maybe,, but but i'd say this is readable and i think readability is gud so i will keep it nice and green,,, green!! :D
550-    char *arg = get_arg(line);
551-
552-    if (strcmp(cmd, "print") == 0) {
553-        cmd_print(cotton, cw, arg);
554-    }
555-
556-    else if (strcmp(cmd, "pixel") == 0) {
557-        cmd_pixel(cotton, cw, arg);
558-    }
559-
560-    else if (strcmp(cmd, "var") == 0) {
561-        cmd_var(cotton, arg);
562-    }
563-
564-    else if (strcmp(cmd, "clear") == 0) {
565-        cmd_clear(cotton, cw);
566-    }
567-
568-    else if (strcmp(cmd, "color") == 0) {
569-        cmd_color(cotton, arg);
570-    }
571-
572-    else if (strcmp(cmd, "wait") == 0) {
573-        cmd_wait(cotton, arg);
574-    }
575-
576-    else if (strcmp(cmd, "input") == 0) {
577-        cmd_input(cotton, arg);
578-    }
579-
580-    else if (strcmp(cmd, "kill") == 0) {
581-        cmd_kill();
582-    }
583-
584-    else if (strcmp(cmd, "add") == 0) {
585-        cmd_math(cotton, arg, '+');
586-    }
587-
588-    else if (strcmp(cmd, "sub") == 0) {
589-        cmd_math(cotton, arg, '-');
590-    }
591-
592-    else if (strcmp(cmd, "mult") == 0) {
593-        cmd_math(cotton, arg, '*');
594-    }
595+        else if (strcmp(tok, "kill") == 0) {
596+            exit(0);
597+        }
598 
599-    else if (strcmp(cmd, "div") == 0) {
600-        cmd_math(cotton, arg, '/');
601-    }
602+        else {
603+            int slot = find_var(c, tok);
604+            if (slot >= 0) {
605+                push(c, slot);
606+            }
607 
608-    else {
609-        cmd_unknown(cmd);
610+            else {
611+                fprintf(stderr, "cot: cotton doesn't know what \"%s\" means, maybe type that out again? :<", tok);
612+            }
613+        }
614+        
615+        tok = strtok(NULL, " ");
616     }
617 }