16f6046cfSSam Ravnborg /* 26f6046cfSSam Ravnborg * textbox.c -- implements the text box 36f6046cfSSam Ravnborg * 46f6046cfSSam Ravnborg * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) 56f6046cfSSam Ravnborg * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) 66f6046cfSSam Ravnborg * 76f6046cfSSam Ravnborg * This program is free software; you can redistribute it and/or 86f6046cfSSam Ravnborg * modify it under the terms of the GNU General Public License 96f6046cfSSam Ravnborg * as published by the Free Software Foundation; either version 2 106f6046cfSSam Ravnborg * of the License, or (at your option) any later version. 116f6046cfSSam Ravnborg * 126f6046cfSSam Ravnborg * This program is distributed in the hope that it will be useful, 136f6046cfSSam Ravnborg * but WITHOUT ANY WARRANTY; without even the implied warranty of 146f6046cfSSam Ravnborg * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 156f6046cfSSam Ravnborg * GNU General Public License for more details. 166f6046cfSSam Ravnborg * 176f6046cfSSam Ravnborg * You should have received a copy of the GNU General Public License 186f6046cfSSam Ravnborg * along with this program; if not, write to the Free Software 196f6046cfSSam Ravnborg * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 206f6046cfSSam Ravnborg */ 216f6046cfSSam Ravnborg 226f6046cfSSam Ravnborg #include "dialog.h" 236f6046cfSSam Ravnborg 246f6046cfSSam Ravnborg static void back_lines(int n); 256f6046cfSSam Ravnborg static void print_page(WINDOW * win, int height, int width); 266f6046cfSSam Ravnborg static void print_line(WINDOW * win, int row, int width); 276f6046cfSSam Ravnborg static char *get_line(void); 28c8dc68adSSam Ravnborg static void print_position(WINDOW * win); 296f6046cfSSam Ravnborg 302982de69SSam Ravnborg static int hscroll; 312982de69SSam Ravnborg static int begin_reached, end_reached, page_length; 322982de69SSam Ravnborg static const char *buf; 332982de69SSam Ravnborg static const char *page; 346f6046cfSSam Ravnborg 356f6046cfSSam Ravnborg /* 36c8dc68adSSam Ravnborg * refresh window content 37c8dc68adSSam Ravnborg */ 38c8dc68adSSam Ravnborg static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw, 39c8dc68adSSam Ravnborg int cur_y, int cur_x) 40c8dc68adSSam Ravnborg { 41c8dc68adSSam Ravnborg print_page(box, boxh, boxw); 42c8dc68adSSam Ravnborg print_position(dialog); 43c8dc68adSSam Ravnborg wmove(dialog, cur_y, cur_x); /* Restore cursor position */ 44c8dc68adSSam Ravnborg wrefresh(dialog); 45c8dc68adSSam Ravnborg } 46c8dc68adSSam Ravnborg 47c8dc68adSSam Ravnborg 48c8dc68adSSam Ravnborg /* 496f6046cfSSam Ravnborg * Display text from a file in a dialog box. 506f6046cfSSam Ravnborg */ 51c8dc68adSSam Ravnborg int dialog_textbox(const char *title, const char *tbuf, 52c8dc68adSSam Ravnborg int initial_height, int initial_width) 536f6046cfSSam Ravnborg { 542982de69SSam Ravnborg int i, x, y, cur_x, cur_y, key = 0; 55c8dc68adSSam Ravnborg int height, width, boxh, boxw; 566f6046cfSSam Ravnborg int passed_end; 57c8dc68adSSam Ravnborg WINDOW *dialog, *box; 586f6046cfSSam Ravnborg 592982de69SSam Ravnborg begin_reached = 1; 602982de69SSam Ravnborg end_reached = 0; 612982de69SSam Ravnborg page_length = 0; 622982de69SSam Ravnborg hscroll = 0; 632982de69SSam Ravnborg buf = tbuf; 646f6046cfSSam Ravnborg page = buf; /* page is pointer to start of page to be displayed */ 656f6046cfSSam Ravnborg 66c8dc68adSSam Ravnborg do_resize: 67c8dc68adSSam Ravnborg getmaxyx(stdscr, height, width); 68c8dc68adSSam Ravnborg if (height < 8 || width < 8) 69c8dc68adSSam Ravnborg return -ERRDISPLAYTOOSMALL; 70c8dc68adSSam Ravnborg if (initial_height != 0) 71c8dc68adSSam Ravnborg height = initial_height; 72c8dc68adSSam Ravnborg else 73c8dc68adSSam Ravnborg if (height > 4) 74c8dc68adSSam Ravnborg height -= 4; 75c8dc68adSSam Ravnborg else 76c8dc68adSSam Ravnborg height = 0; 77c8dc68adSSam Ravnborg if (initial_width != 0) 78c8dc68adSSam Ravnborg width = initial_width; 79c8dc68adSSam Ravnborg else 80c8dc68adSSam Ravnborg if (width > 5) 81c8dc68adSSam Ravnborg width -= 5; 82c8dc68adSSam Ravnborg else 83c8dc68adSSam Ravnborg width = 0; 84c8dc68adSSam Ravnborg 856f6046cfSSam Ravnborg /* center dialog box on screen */ 866f6046cfSSam Ravnborg x = (COLS - width) / 2; 876f6046cfSSam Ravnborg y = (LINES - height) / 2; 886f6046cfSSam Ravnborg 896f6046cfSSam Ravnborg draw_shadow(stdscr, y, x, height, width); 906f6046cfSSam Ravnborg 916f6046cfSSam Ravnborg dialog = newwin(height, width, y, x); 926f6046cfSSam Ravnborg keypad(dialog, TRUE); 936f6046cfSSam Ravnborg 94c8dc68adSSam Ravnborg /* Create window for box region, used for scrolling text */ 95c8dc68adSSam Ravnborg boxh = height - 4; 96c8dc68adSSam Ravnborg boxw = width - 2; 97c8dc68adSSam Ravnborg box = subwin(dialog, boxh, boxw, y + 1, x + 1); 98c8dc68adSSam Ravnborg wattrset(box, dlg.dialog.atr); 99c8dc68adSSam Ravnborg wbkgdset(box, dlg.dialog.atr & A_COLOR); 1006f6046cfSSam Ravnborg 101c8dc68adSSam Ravnborg keypad(box, TRUE); 1026f6046cfSSam Ravnborg 1036f6046cfSSam Ravnborg /* register the new window, along with its borders */ 10498e5a157SSam Ravnborg draw_box(dialog, 0, 0, height, width, 10598e5a157SSam Ravnborg dlg.dialog.atr, dlg.border.atr); 1066f6046cfSSam Ravnborg 10798e5a157SSam Ravnborg wattrset(dialog, dlg.border.atr); 1086f6046cfSSam Ravnborg mvwaddch(dialog, height - 3, 0, ACS_LTEE); 1096f6046cfSSam Ravnborg for (i = 0; i < width - 2; i++) 1106f6046cfSSam Ravnborg waddch(dialog, ACS_HLINE); 11198e5a157SSam Ravnborg wattrset(dialog, dlg.dialog.atr); 11298e5a157SSam Ravnborg wbkgdset(dialog, dlg.dialog.atr & A_COLOR); 1136f6046cfSSam Ravnborg waddch(dialog, ACS_RTEE); 1146f6046cfSSam Ravnborg 1156f6046cfSSam Ravnborg print_title(dialog, title, width); 1166f6046cfSSam Ravnborg 11775c0a8a5SEGRY Gabor print_button(dialog, gettext(" Exit "), height - 2, width / 2 - 4, TRUE); 1186f6046cfSSam Ravnborg wnoutrefresh(dialog); 1196f6046cfSSam Ravnborg getyx(dialog, cur_y, cur_x); /* Save cursor position */ 1206f6046cfSSam Ravnborg 1216f6046cfSSam Ravnborg /* Print first page of text */ 122c8dc68adSSam Ravnborg attr_clear(box, boxh, boxw, dlg.dialog.atr); 123c8dc68adSSam Ravnborg refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); 1246f6046cfSSam Ravnborg 125f3cbcdc9SSam Ravnborg while ((key != KEY_ESC) && (key != '\n')) { 1266f6046cfSSam Ravnborg key = wgetch(dialog); 1276f6046cfSSam Ravnborg switch (key) { 1286f6046cfSSam Ravnborg case 'E': /* Exit */ 1296f6046cfSSam Ravnborg case 'e': 1306f6046cfSSam Ravnborg case 'X': 1316f6046cfSSam Ravnborg case 'x': 1329d4792c9SBenjamin Poirier case 'q': 133c8dc68adSSam Ravnborg delwin(box); 1346f6046cfSSam Ravnborg delwin(dialog); 1356f6046cfSSam Ravnborg return 0; 1366f6046cfSSam Ravnborg case 'g': /* First page */ 1376f6046cfSSam Ravnborg case KEY_HOME: 1386f6046cfSSam Ravnborg if (!begin_reached) { 1396f6046cfSSam Ravnborg begin_reached = 1; 1406f6046cfSSam Ravnborg page = buf; 141c8dc68adSSam Ravnborg refresh_text_box(dialog, box, boxh, boxw, 142c8dc68adSSam Ravnborg cur_y, cur_x); 1436f6046cfSSam Ravnborg } 1446f6046cfSSam Ravnborg break; 1456f6046cfSSam Ravnborg case 'G': /* Last page */ 1466f6046cfSSam Ravnborg case KEY_END: 1476f6046cfSSam Ravnborg 1486f6046cfSSam Ravnborg end_reached = 1; 1492982de69SSam Ravnborg /* point to last char in buf */ 1502982de69SSam Ravnborg page = buf + strlen(buf); 151c8dc68adSSam Ravnborg back_lines(boxh); 152c8dc68adSSam Ravnborg refresh_text_box(dialog, box, boxh, boxw, 153c8dc68adSSam Ravnborg cur_y, cur_x); 1546f6046cfSSam Ravnborg break; 1556f6046cfSSam Ravnborg case 'K': /* Previous line */ 1566f6046cfSSam Ravnborg case 'k': 1576f6046cfSSam Ravnborg case KEY_UP: 1586f6046cfSSam Ravnborg if (!begin_reached) { 1596f6046cfSSam Ravnborg back_lines(page_length + 1); 1606f6046cfSSam Ravnborg 1612982de69SSam Ravnborg /* We don't call print_page() here but use 1622982de69SSam Ravnborg * scrolling to ensure faster screen update. 1632982de69SSam Ravnborg * However, 'end_reached' and 'page_length' 1642982de69SSam Ravnborg * should still be updated, and 'page' should 1652982de69SSam Ravnborg * point to start of next page. This is done 1662982de69SSam Ravnborg * by calling get_line() in the following 1672982de69SSam Ravnborg * 'for' loop. */ 168c8dc68adSSam Ravnborg scrollok(box, TRUE); 169c8dc68adSSam Ravnborg wscrl(box, -1); /* Scroll box region down one line */ 170c8dc68adSSam Ravnborg scrollok(box, FALSE); 1716f6046cfSSam Ravnborg page_length = 0; 1726f6046cfSSam Ravnborg passed_end = 0; 173c8dc68adSSam Ravnborg for (i = 0; i < boxh; i++) { 1746f6046cfSSam Ravnborg if (!i) { 1756f6046cfSSam Ravnborg /* print first line of page */ 176c8dc68adSSam Ravnborg print_line(box, 0, boxw); 177c8dc68adSSam Ravnborg wnoutrefresh(box); 1786f6046cfSSam Ravnborg } else 1796f6046cfSSam Ravnborg /* Called to update 'end_reached' and 'page' */ 1806f6046cfSSam Ravnborg get_line(); 1816f6046cfSSam Ravnborg if (!passed_end) 1826f6046cfSSam Ravnborg page_length++; 1836f6046cfSSam Ravnborg if (end_reached && !passed_end) 1846f6046cfSSam Ravnborg passed_end = 1; 1856f6046cfSSam Ravnborg } 1866f6046cfSSam Ravnborg 187c8dc68adSSam Ravnborg print_position(dialog); 1886f6046cfSSam Ravnborg wmove(dialog, cur_y, cur_x); /* Restore cursor position */ 1896f6046cfSSam Ravnborg wrefresh(dialog); 1906f6046cfSSam Ravnborg } 1916f6046cfSSam Ravnborg break; 1926f6046cfSSam Ravnborg case 'B': /* Previous page */ 1936f6046cfSSam Ravnborg case 'b': 1949d4792c9SBenjamin Poirier case 'u': 1956f6046cfSSam Ravnborg case KEY_PPAGE: 1966f6046cfSSam Ravnborg if (begin_reached) 1976f6046cfSSam Ravnborg break; 198c8dc68adSSam Ravnborg back_lines(page_length + boxh); 199c8dc68adSSam Ravnborg refresh_text_box(dialog, box, boxh, boxw, 200c8dc68adSSam Ravnborg cur_y, cur_x); 2016f6046cfSSam Ravnborg break; 2026f6046cfSSam Ravnborg case 'J': /* Next line */ 2036f6046cfSSam Ravnborg case 'j': 2046f6046cfSSam Ravnborg case KEY_DOWN: 2056f6046cfSSam Ravnborg if (!end_reached) { 2066f6046cfSSam Ravnborg begin_reached = 0; 207c8dc68adSSam Ravnborg scrollok(box, TRUE); 208c8dc68adSSam Ravnborg scroll(box); /* Scroll box region up one line */ 209c8dc68adSSam Ravnborg scrollok(box, FALSE); 210c8dc68adSSam Ravnborg print_line(box, boxh - 1, boxw); 211c8dc68adSSam Ravnborg wnoutrefresh(box); 212c8dc68adSSam Ravnborg print_position(dialog); 2136f6046cfSSam Ravnborg wmove(dialog, cur_y, cur_x); /* Restore cursor position */ 2146f6046cfSSam Ravnborg wrefresh(dialog); 2156f6046cfSSam Ravnborg } 2166f6046cfSSam Ravnborg break; 2176f6046cfSSam Ravnborg case KEY_NPAGE: /* Next page */ 2186f6046cfSSam Ravnborg case ' ': 2199d4792c9SBenjamin Poirier case 'd': 2206f6046cfSSam Ravnborg if (end_reached) 2216f6046cfSSam Ravnborg break; 2226f6046cfSSam Ravnborg 2236f6046cfSSam Ravnborg begin_reached = 0; 224c8dc68adSSam Ravnborg refresh_text_box(dialog, box, boxh, boxw, 225c8dc68adSSam Ravnborg cur_y, cur_x); 2266f6046cfSSam Ravnborg break; 2276f6046cfSSam Ravnborg case '0': /* Beginning of line */ 2286f6046cfSSam Ravnborg case 'H': /* Scroll left */ 2296f6046cfSSam Ravnborg case 'h': 2306f6046cfSSam Ravnborg case KEY_LEFT: 2316f6046cfSSam Ravnborg if (hscroll <= 0) 2326f6046cfSSam Ravnborg break; 2336f6046cfSSam Ravnborg 2346f6046cfSSam Ravnborg if (key == '0') 2356f6046cfSSam Ravnborg hscroll = 0; 2366f6046cfSSam Ravnborg else 2376f6046cfSSam Ravnborg hscroll--; 2386f6046cfSSam Ravnborg /* Reprint current page to scroll horizontally */ 2396f6046cfSSam Ravnborg back_lines(page_length); 240c8dc68adSSam Ravnborg refresh_text_box(dialog, box, boxh, boxw, 241c8dc68adSSam Ravnborg cur_y, cur_x); 2426f6046cfSSam Ravnborg break; 2436f6046cfSSam Ravnborg case 'L': /* Scroll right */ 2446f6046cfSSam Ravnborg case 'l': 2456f6046cfSSam Ravnborg case KEY_RIGHT: 2466f6046cfSSam Ravnborg if (hscroll >= MAX_LEN) 2476f6046cfSSam Ravnborg break; 2486f6046cfSSam Ravnborg hscroll++; 2496f6046cfSSam Ravnborg /* Reprint current page to scroll horizontally */ 2506f6046cfSSam Ravnborg back_lines(page_length); 251c8dc68adSSam Ravnborg refresh_text_box(dialog, box, boxh, boxw, 252c8dc68adSSam Ravnborg cur_y, cur_x); 2536f6046cfSSam Ravnborg break; 254f3cbcdc9SSam Ravnborg case KEY_ESC: 255f3cbcdc9SSam Ravnborg key = on_key_esc(dialog); 2566f6046cfSSam Ravnborg break; 257c8dc68adSSam Ravnborg case KEY_RESIZE: 258c8dc68adSSam Ravnborg back_lines(height); 259c8dc68adSSam Ravnborg delwin(box); 260c8dc68adSSam Ravnborg delwin(dialog); 261c8dc68adSSam Ravnborg on_key_resize(); 262c8dc68adSSam Ravnborg goto do_resize; 2636f6046cfSSam Ravnborg } 2646f6046cfSSam Ravnborg } 265c8dc68adSSam Ravnborg delwin(box); 2666f6046cfSSam Ravnborg delwin(dialog); 267f3cbcdc9SSam Ravnborg return key; /* ESC pressed */ 2686f6046cfSSam Ravnborg } 2696f6046cfSSam Ravnborg 2706f6046cfSSam Ravnborg /* 2712982de69SSam Ravnborg * Go back 'n' lines in text. Called by dialog_textbox(). 2726f6046cfSSam Ravnborg * 'page' will be updated to point to the desired line in 'buf'. 2736f6046cfSSam Ravnborg */ 2746f6046cfSSam Ravnborg static void back_lines(int n) 2756f6046cfSSam Ravnborg { 2762982de69SSam Ravnborg int i; 2776f6046cfSSam Ravnborg 2786f6046cfSSam Ravnborg begin_reached = 0; 2792982de69SSam Ravnborg /* Go back 'n' lines */ 2802982de69SSam Ravnborg for (i = 0; i < n; i++) { 2812982de69SSam Ravnborg if (*page == '\0') { 2822982de69SSam Ravnborg if (end_reached) { 2832982de69SSam Ravnborg end_reached = 0; 2842982de69SSam Ravnborg continue; 2852982de69SSam Ravnborg } 2862982de69SSam Ravnborg } 2876f6046cfSSam Ravnborg if (page == buf) { 2886f6046cfSSam Ravnborg begin_reached = 1; 2896f6046cfSSam Ravnborg return; 2906f6046cfSSam Ravnborg } 2912982de69SSam Ravnborg page--; 2926f6046cfSSam Ravnborg do { 2936f6046cfSSam Ravnborg if (page == buf) { 2946f6046cfSSam Ravnborg begin_reached = 1; 2956f6046cfSSam Ravnborg return; 2966f6046cfSSam Ravnborg } 2972982de69SSam Ravnborg page--; 2982982de69SSam Ravnborg } while (*page != '\n'); 2996f6046cfSSam Ravnborg page++; 3006f6046cfSSam Ravnborg } 3012982de69SSam Ravnborg } 3026f6046cfSSam Ravnborg 3036f6046cfSSam Ravnborg /* 3046f6046cfSSam Ravnborg * Print a new page of text. Called by dialog_textbox(). 3056f6046cfSSam Ravnborg */ 3066f6046cfSSam Ravnborg static void print_page(WINDOW * win, int height, int width) 3076f6046cfSSam Ravnborg { 3086f6046cfSSam Ravnborg int i, passed_end = 0; 3096f6046cfSSam Ravnborg 3106f6046cfSSam Ravnborg page_length = 0; 3116f6046cfSSam Ravnborg for (i = 0; i < height; i++) { 3126f6046cfSSam Ravnborg print_line(win, i, width); 3136f6046cfSSam Ravnborg if (!passed_end) 3146f6046cfSSam Ravnborg page_length++; 3156f6046cfSSam Ravnborg if (end_reached && !passed_end) 3166f6046cfSSam Ravnborg passed_end = 1; 3176f6046cfSSam Ravnborg } 3186f6046cfSSam Ravnborg wnoutrefresh(win); 3196f6046cfSSam Ravnborg } 3206f6046cfSSam Ravnborg 3216f6046cfSSam Ravnborg /* 3226f6046cfSSam Ravnborg * Print a new line of text. Called by dialog_textbox() and print_page(). 3236f6046cfSSam Ravnborg */ 3246f6046cfSSam Ravnborg static void print_line(WINDOW * win, int row, int width) 3256f6046cfSSam Ravnborg { 3266f6046cfSSam Ravnborg char *line; 3276f6046cfSSam Ravnborg 3286f6046cfSSam Ravnborg line = get_line(); 3296f6046cfSSam Ravnborg line += MIN(strlen(line), hscroll); /* Scroll horizontally */ 3306f6046cfSSam Ravnborg wmove(win, row, 0); /* move cursor to correct line */ 3316f6046cfSSam Ravnborg waddch(win, ' '); 3326f6046cfSSam Ravnborg waddnstr(win, line, MIN(strlen(line), width - 2)); 3336f6046cfSSam Ravnborg 3346f6046cfSSam Ravnborg /* Clear 'residue' of previous line */ 3356f6046cfSSam Ravnborg #if OLD_NCURSES 3366f6046cfSSam Ravnborg { 337702a9450SLucas De Marchi int x = getcurx(win); 3386f6046cfSSam Ravnborg int i; 3396f6046cfSSam Ravnborg for (i = 0; i < width - x; i++) 3406f6046cfSSam Ravnborg waddch(win, ' '); 3416f6046cfSSam Ravnborg } 3426f6046cfSSam Ravnborg #else 3436f6046cfSSam Ravnborg wclrtoeol(win); 3446f6046cfSSam Ravnborg #endif 3456f6046cfSSam Ravnborg } 3466f6046cfSSam Ravnborg 3476f6046cfSSam Ravnborg /* 3486f6046cfSSam Ravnborg * Return current line of text. Called by dialog_textbox() and print_line(). 3496f6046cfSSam Ravnborg * 'page' should point to start of current line before calling, and will be 3506f6046cfSSam Ravnborg * updated to point to start of next line. 3516f6046cfSSam Ravnborg */ 3526f6046cfSSam Ravnborg static char *get_line(void) 3536f6046cfSSam Ravnborg { 3542982de69SSam Ravnborg int i = 0; 3556f6046cfSSam Ravnborg static char line[MAX_LEN + 1]; 3566f6046cfSSam Ravnborg 3576f6046cfSSam Ravnborg end_reached = 0; 3586f6046cfSSam Ravnborg while (*page != '\n') { 3596f6046cfSSam Ravnborg if (*page == '\0') { 3606f6046cfSSam Ravnborg end_reached = 1; 3616f6046cfSSam Ravnborg break; 3626f6046cfSSam Ravnborg } else if (i < MAX_LEN) 3636f6046cfSSam Ravnborg line[i++] = *(page++); 3646f6046cfSSam Ravnborg else { 3656f6046cfSSam Ravnborg /* Truncate lines longer than MAX_LEN characters */ 3666f6046cfSSam Ravnborg if (i == MAX_LEN) 3676f6046cfSSam Ravnborg line[i++] = '\0'; 3686f6046cfSSam Ravnborg page++; 3696f6046cfSSam Ravnborg } 3706f6046cfSSam Ravnborg } 3716f6046cfSSam Ravnborg if (i <= MAX_LEN) 3726f6046cfSSam Ravnborg line[i] = '\0'; 3736f6046cfSSam Ravnborg if (!end_reached) 374b9d29abdSBenjamin Poirier page++; /* move past '\n' */ 3756f6046cfSSam Ravnborg 3766f6046cfSSam Ravnborg return line; 3776f6046cfSSam Ravnborg } 3786f6046cfSSam Ravnborg 3796f6046cfSSam Ravnborg /* 3806f6046cfSSam Ravnborg * Print current position 3816f6046cfSSam Ravnborg */ 382c8dc68adSSam Ravnborg static void print_position(WINDOW * win) 3836f6046cfSSam Ravnborg { 3842982de69SSam Ravnborg int percent; 3856f6046cfSSam Ravnborg 38698e5a157SSam Ravnborg wattrset(win, dlg.position_indicator.atr); 38798e5a157SSam Ravnborg wbkgdset(win, dlg.position_indicator.atr & A_COLOR); 3882982de69SSam Ravnborg percent = (page - buf) * 100 / strlen(buf); 389c8dc68adSSam Ravnborg wmove(win, getmaxy(win) - 3, getmaxx(win) - 9); 3906f6046cfSSam Ravnborg wprintw(win, "(%3d%%)", percent); 3916f6046cfSSam Ravnborg } 392