Commit f1ab6ef137e74d35fd17edda4a0c713ab97f20ad
1 parent
18901d25
Exists in
master
and in
3 other branches
Implementando seleção pela biblioteca
Showing
5 changed files
with
100 additions
and
300 deletions
Show diff stats
Makefile.in
| @@ -74,7 +74,8 @@ SOURCES = XtGlue.c actions.c ansi.c charset.c ctlr.c \ | @@ -74,7 +74,8 @@ SOURCES = XtGlue.c actions.c ansi.c charset.c ctlr.c \ | ||
| 74 | ft.c ft_cut.c ft_dft.c glue.c host.c kybd.c \ | 74 | ft.c ft_cut.c ft_dft.c glue.c host.c kybd.c \ |
| 75 | print.c printer.c proxy.c resources.c rpq.c screen.c see.c \ | 75 | print.c printer.c proxy.c resources.c rpq.c screen.c see.c \ |
| 76 | sf.c tables.c telnet.c toggles.c trace_ds.c utf8.c util.c \ | 76 | sf.c tables.c telnet.c toggles.c trace_ds.c utf8.c util.c \ |
| 77 | - xio.c resolver.c log.c paste.c macros.c fallbacks.c version.c | 77 | + xio.c resolver.c log.c paste.c macros.c fallbacks.c version.c \ |
| 78 | + selection.c | ||
| 78 | 79 | ||
| 79 | #---[ Misc targets ]----------------------------------------------------------- | 80 | #---[ Misc targets ]----------------------------------------------------------- |
| 80 | 81 |
glue.c
| @@ -175,11 +175,12 @@ static void lib3270_session_init(H3270 *hSession, const char *model) | @@ -175,11 +175,12 @@ static void lib3270_session_init(H3270 *hSession, const char *model) | ||
| 175 | hSession->sz = sizeof(H3270); | 175 | hSession->sz = sizeof(H3270); |
| 176 | hSession->sock = -1; | 176 | hSession->sock = -1; |
| 177 | hSession->model_num = -1; | 177 | hSession->model_num = -1; |
| 178 | -// hSession->first_changed = -1; | ||
| 179 | -// hSession->last_changed = -1; | ||
| 180 | hSession->cstate = NOT_CONNECTED; | 178 | hSession->cstate = NOT_CONNECTED; |
| 181 | hSession->oia_status = -1; | 179 | hSession->oia_status = -1; |
| 182 | 180 | ||
| 181 | + hSession->selected.begin = -1; | ||
| 182 | + hSession->selected.end = -1; | ||
| 183 | + | ||
| 183 | strncpy(hSession->full_model_name,"IBM-",LIB3270_FULL_MODEL_NAME_LENGTH); | 184 | strncpy(hSession->full_model_name,"IBM-",LIB3270_FULL_MODEL_NAME_LENGTH); |
| 184 | hSession->model_name = &hSession->full_model_name[4]; | 185 | hSession->model_name = &hSession->full_model_name[4]; |
| 185 | 186 |
kybd.c
| @@ -2945,301 +2945,6 @@ LIB3270_ACTION( fieldend ) | @@ -2945,301 +2945,6 @@ LIB3270_ACTION( fieldend ) | ||
| 2945 | return 0; | 2945 | return 0; |
| 2946 | } | 2946 | } |
| 2947 | 2947 | ||
| 2948 | -/* | ||
| 2949 | - * MoveCursor action. Depending on arguments, this is either a move to the | ||
| 2950 | - * mouse cursor position, or to an absolute location. | ||
| 2951 | - */ /* | ||
| 2952 | -void | ||
| 2953 | -MoveCursor_action(Widget w, XEvent *event, String *params, Cardinal *num_params) | ||
| 2954 | -{ | ||
| 2955 | - register int baddr; | ||
| 2956 | - int row, col; | ||
| 2957 | - | ||
| 2958 | -// reset_idle_timer(); | ||
| 2959 | - if (kybdlock) { | ||
| 2960 | - if (*num_params == 2) | ||
| 2961 | - enq_ta(MoveCursor_action, params[0], params[1]); | ||
| 2962 | - return; | ||
| 2963 | - } | ||
| 2964 | - | ||
| 2965 | - switch (*num_params) { | ||
| 2966 | -#if defined(X3270_DISPLAY | ||
| 2967 | - case 0: // mouse click, presumably | ||
| 2968 | - if (w != *screen) | ||
| 2969 | - return; | ||
| 2970 | - cursor_move(mouse_baddr(w, event)); | ||
| 2971 | - break; | ||
| 2972 | -#endif | ||
| 2973 | - case 2: // probably a macro call | ||
| 2974 | - row = atoi(params[0]); | ||
| 2975 | - col = atoi(params[1]); | ||
| 2976 | - if (!IN_3270) { | ||
| 2977 | - row--; | ||
| 2978 | - col--; | ||
| 2979 | - } | ||
| 2980 | - if (row < 0) | ||
| 2981 | - row = 0; | ||
| 2982 | - if (col < 0) | ||
| 2983 | - col = 0; | ||
| 2984 | - baddr = ((row * COLS) + col) % (ROWS * COLS); | ||
| 2985 | - cursor_move(baddr); | ||
| 2986 | - break; | ||
| 2987 | - default: // couln't say | ||
| 2988 | - popup_an_error("%s requires 0 or 2 arguments", | ||
| 2989 | - action_name(MoveCursor_action)); | ||
| 2990 | -// cancel_if_idle_command(); | ||
| 2991 | - break; | ||
| 2992 | - } | ||
| 2993 | -} | ||
| 2994 | - | ||
| 2995 | -*/ | ||
| 2996 | -#if defined(X3270_DBCS) && defined(X3270_DISPLAY) /*[*/ | ||
| 2997 | -/* | ||
| 2998 | - * Run a KeyPress through XIM. | ||
| 2999 | - * Returns True if there is further processing to do, False otherwise. | ||
| 3000 | - */ /* | ||
| 3001 | -static Boolean | ||
| 3002 | -xim_lookup(XKeyEvent *event) | ||
| 3003 | -{ | ||
| 3004 | - static char *buf = NULL; | ||
| 3005 | - static UChar *Ubuf = NULL; | ||
| 3006 | - static int buf_len = 0, rlen; | ||
| 3007 | - KeySym k; | ||
| 3008 | - Status status; | ||
| 3009 | - extern XIC ic; | ||
| 3010 | - int i; | ||
| 3011 | - Boolean rv = False; | ||
| 3012 | - int wlen; | ||
| 3013 | -#define BASE_BUFSIZE 50 | ||
| 3014 | - | ||
| 3015 | - if (ic == NULL) | ||
| 3016 | - return True; | ||
| 3017 | - | ||
| 3018 | - if (buf == NULL) { | ||
| 3019 | - buf_len = BASE_BUFSIZE; | ||
| 3020 | - buf = Malloc(buf_len); | ||
| 3021 | - Ubuf = (UChar *)Malloc(buf_len * sizeof(UChar)); | ||
| 3022 | - } | ||
| 3023 | - | ||
| 3024 | - for (;;) { | ||
| 3025 | - memset(buf, '\0', buf_len); | ||
| 3026 | - rlen = XmbLookupString(ic, event, buf, buf_len - 1, &k, | ||
| 3027 | - &status); | ||
| 3028 | - if (status != XBufferOverflow) | ||
| 3029 | - break; | ||
| 3030 | - buf_len += BASE_BUFSIZE; | ||
| 3031 | - buf = Realloc(buf, buf_len); | ||
| 3032 | - Ubuf = (UChar *)Realloc(Ubuf, buf_len * sizeof(UChar)); | ||
| 3033 | - } | ||
| 3034 | - | ||
| 3035 | - switch (status) { | ||
| 3036 | - case XLookupNone: | ||
| 3037 | - rv = False; | ||
| 3038 | - break; | ||
| 3039 | - case XLookupKeySym: | ||
| 3040 | - rv = True; | ||
| 3041 | - break; | ||
| 3042 | - case XLookupChars: | ||
| 3043 | - trace_event("%d XIM char%s:", rlen, (rlen != 1)? "s": ""); | ||
| 3044 | - for (i = 0; i < rlen; i++) { | ||
| 3045 | - trace_event(" %02x", buf[i] & 0xff); | ||
| 3046 | - } | ||
| 3047 | - trace_event("\n"); | ||
| 3048 | - wlen = mb_to_unicode(buf, rlen, Ubuf, buf_len, NULL); | ||
| 3049 | - if (wlen < 0) | ||
| 3050 | - trace_event(" conversion failed\n"); | ||
| 3051 | - for (i = 0; i < wlen; i++) { | ||
| 3052 | - unsigned char asc; | ||
| 3053 | - unsigned char ebc[2]; | ||
| 3054 | - | ||
| 3055 | - if (dbcs_map8(Ubuf[i], &asc)) { | ||
| 3056 | - trace_event(" U+%04x -> " | ||
| 3057 | - "EBCDIC SBCS X'%02x'\n", | ||
| 3058 | - Ubuf[i] & 0xffff, asc2ebc[asc]); | ||
| 3059 | - key_ACharacter(asc, KT_STD, ia_cause, NULL); | ||
| 3060 | - } else if (dbcs_map16(Ubuf[i], ebc)) { | ||
| 3061 | - trace_event(" U+%04x -> " | ||
| 3062 | - "EBCDIC DBCS X'%02x%02x'\n", | ||
| 3063 | - Ubuf[i] & 0xffff, ebc[0], ebc[1]); | ||
| 3064 | - (void) key_WCharacter(ebc, NULL); | ||
| 3065 | - } else | ||
| 3066 | - trace_event(" Cannot convert U+%04x to " | ||
| 3067 | - "EBCDIC\n", Ubuf[i] & 0xffff); | ||
| 3068 | - } | ||
| 3069 | - rv = False; | ||
| 3070 | - break; | ||
| 3071 | - case XLookupBoth: | ||
| 3072 | - rv = True; | ||
| 3073 | - break; | ||
| 3074 | - } | ||
| 3075 | - return rv; | ||
| 3076 | -} | ||
| 3077 | -*/ | ||
| 3078 | -#endif | ||
| 3079 | - | ||
| 3080 | -/* | ||
| 3081 | - * Key action by string | ||
| 3082 | - */ /* | ||
| 3083 | -void Input_String(const unsigned char *str) | ||
| 3084 | -{ | ||
| 3085 | -// reset_idle_timer(); | ||
| 3086 | - | ||
| 3087 | - // FIXME (perry#3#): It works but, is it right? | ||
| 3088 | - while(*str) | ||
| 3089 | - { | ||
| 3090 | - key_ACharacter((unsigned char)((*str) & 0xff), KT_STD, IA_KEY, NULL); | ||
| 3091 | - str++; | ||
| 3092 | - } | ||
| 3093 | - screen_disp(&h3270); | ||
| 3094 | -} */ | ||
| 3095 | - | ||
| 3096 | -/* | ||
| 3097 | - * Key action. | ||
| 3098 | - */ /* | ||
| 3099 | -void | ||
| 3100 | -Key_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params) | ||
| 3101 | -{ | ||
| 3102 | - Cardinal i; | ||
| 3103 | - KeySym k; | ||
| 3104 | - enum keytype keytype; | ||
| 3105 | - | ||
| 3106 | -// reset_idle_timer(); | ||
| 3107 | - | ||
| 3108 | - for (i = 0; i < *num_params; i++) { | ||
| 3109 | - char *s = params[i]; | ||
| 3110 | - | ||
| 3111 | - k = MyStringToKeysym(s, &keytype); | ||
| 3112 | - if (k == NoSymbol) { | ||
| 3113 | - popup_an_error("%s: Nonexistent or invalid KeySym: %s", | ||
| 3114 | - action_name(Key_action), s); | ||
| 3115 | -// cancel_if_idle_command(); | ||
| 3116 | - continue; | ||
| 3117 | - } | ||
| 3118 | - if (k & ~0xff) { | ||
| 3119 | - popup_an_error("%s: Invalid KeySym: %s", | ||
| 3120 | - action_name(Key_action), s); | ||
| 3121 | -// cancel_if_idle_command(); | ||
| 3122 | - continue; | ||
| 3123 | - } | ||
| 3124 | - key_ACharacter((unsigned char)(k & 0xff), keytype, IA_KEY, | ||
| 3125 | - NULL); | ||
| 3126 | - } | ||
| 3127 | -} | ||
| 3128 | -*/ | ||
| 3129 | -/* | ||
| 3130 | - * String action. | ||
| 3131 | - */ /* | ||
| 3132 | -void | ||
| 3133 | -String_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params) | ||
| 3134 | -{ | ||
| 3135 | - Cardinal i; | ||
| 3136 | - int len = 0; | ||
| 3137 | - char *s0, *s; | ||
| 3138 | - | ||
| 3139 | -// reset_idle_timer(); | ||
| 3140 | - | ||
| 3141 | - // Determine the total length of the strings. | ||
| 3142 | - for (i = 0; i < *num_params; i++) | ||
| 3143 | - len += strlen(params[i]); | ||
| 3144 | - if (!len) | ||
| 3145 | - return; | ||
| 3146 | - | ||
| 3147 | - // Allocate a block of memory and copy them in. | ||
| 3148 | - s0 = s = Malloc(len + 1); | ||
| 3149 | - *s = '\0'; | ||
| 3150 | - for (i = 0; i < *num_params; i++) { | ||
| 3151 | - char *t = params[i]; | ||
| 3152 | - unsigned char c; | ||
| 3153 | - | ||
| 3154 | - while ((c = (unsigned char)*t) != '\0') { | ||
| 3155 | - if (c & 0x80) { | ||
| 3156 | - unsigned char xc; | ||
| 3157 | - enum ulfail fail; | ||
| 3158 | - int consumed; | ||
| 3159 | - | ||
| 3160 | - xc = utf8_lookup(t, &fail, &consumed); | ||
| 3161 | - if (xc == 0) { | ||
| 3162 | - switch (fail) { | ||
| 3163 | - case ULFAIL_NOUTF8: | ||
| 3164 | - *s++ = (char)c; | ||
| 3165 | - break; | ||
| 3166 | - case ULFAIL_INCOMPLETE: | ||
| 3167 | - case ULFAIL_INVALID: | ||
| 3168 | - *s++ = ' '; | ||
| 3169 | - break; | ||
| 3170 | - } | ||
| 3171 | - } else { | ||
| 3172 | - *s++ = (char)xc; | ||
| 3173 | - t += (consumed - 1); | ||
| 3174 | - } | ||
| 3175 | - } else | ||
| 3176 | - *s++ = (char)c; | ||
| 3177 | - t++; | ||
| 3178 | - } | ||
| 3179 | - } | ||
| 3180 | - *s = '\0'; | ||
| 3181 | - | ||
| 3182 | - // Set a pending string. | ||
| 3183 | -// ps_set(s0, False); | ||
| 3184 | -} | ||
| 3185 | -*/ | ||
| 3186 | - | ||
| 3187 | -/* | ||
| 3188 | - * HexString action. | ||
| 3189 | - */ /* | ||
| 3190 | -void HexString_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params) | ||
| 3191 | -{ | ||
| 3192 | - Cardinal i; | ||
| 3193 | - int len = 0; | ||
| 3194 | - char *s; | ||
| 3195 | - char *t; | ||
| 3196 | - | ||
| 3197 | -// reset_idle_timer(); | ||
| 3198 | - | ||
| 3199 | - // Determine the total length of the strings. | ||
| 3200 | - for (i = 0; i < *num_params; i++) { | ||
| 3201 | - t = params[i]; | ||
| 3202 | - if (!strncmp(t, "0x", 2) || !strncmp(t, "0X", 2)) | ||
| 3203 | - t += 2; | ||
| 3204 | - len += strlen(t); | ||
| 3205 | - } | ||
| 3206 | - if (!len) | ||
| 3207 | - return; | ||
| 3208 | - | ||
| 3209 | - // Allocate a block of memory and copy them in. | ||
| 3210 | - s = Malloc(len + 1); | ||
| 3211 | - *s = '\0'; | ||
| 3212 | - for (i = 0; i < *num_params; i++) { | ||
| 3213 | - t = params[i]; | ||
| 3214 | - if (!strncmp(t, "0x", 2) || !strncmp(t, "0X", 2)) | ||
| 3215 | - t += 2; | ||
| 3216 | - (void) strcat(s, t); | ||
| 3217 | - } | ||
| 3218 | - | ||
| 3219 | - // Set a pending string. | ||
| 3220 | -// ps_set(s, True); | ||
| 3221 | -} | ||
| 3222 | -*/ | ||
| 3223 | - | ||
| 3224 | -/* | ||
| 3225 | - * Dual-mode action for the "asciicircum" ("^") key: | ||
| 3226 | - * If in ANSI mode, pass through untranslated. | ||
| 3227 | - * If in 3270 mode, translate to "notsign". | ||
| 3228 | - * This action is obsoleted by the use of 3270-mode and NVT-mode keymaps, but | ||
| 3229 | - * is still defined here for backwards compatibility with old keymaps. | ||
| 3230 | - */ /* | ||
| 3231 | -void | ||
| 3232 | -CircumNot_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params) | ||
| 3233 | -{ | ||
| 3234 | -// reset_idle_timer(); | ||
| 3235 | - | ||
| 3236 | - if (IN_3270 && composing == NONE) | ||
| 3237 | - key_ACharacter(0xac, KT_STD, IA_KEY, NULL); | ||
| 3238 | - else | ||
| 3239 | - key_ACharacter('^', KT_STD, IA_KEY, NULL); | ||
| 3240 | -} | ||
| 3241 | -*/ | ||
| 3242 | - | ||
| 3243 | /* PA key action for String actions */ | 2948 | /* PA key action for String actions */ |
| 3244 | static void | 2949 | static void |
| 3245 | do_pa(unsigned n) | 2950 | do_pa(unsigned n) |
screen.c
| @@ -740,9 +740,9 @@ void popup_system_error(H3270 *session, const char *title, const char *message, | @@ -740,9 +740,9 @@ void popup_system_error(H3270 *session, const char *title, const char *message, | ||
| 740 | va_end(args); | 740 | va_end(args); |
| 741 | } | 741 | } |
| 742 | 742 | ||
| 743 | +/* | ||
| 743 | LIB3270_EXPORT void update_toggle_actions(void) | 744 | LIB3270_EXPORT void update_toggle_actions(void) |
| 744 | { | 745 | { |
| 745 | -/* | ||
| 746 | int f; | 746 | int f; |
| 747 | 747 | ||
| 748 | if(callbacks && callbacks->toggle_changed) | 748 | if(callbacks && callbacks->toggle_changed) |
| @@ -750,8 +750,8 @@ LIB3270_EXPORT void update_toggle_actions(void) | @@ -750,8 +750,8 @@ LIB3270_EXPORT void update_toggle_actions(void) | ||
| 750 | for(f=0;f< N_TOGGLES;f++) | 750 | for(f=0;f< N_TOGGLES;f++) |
| 751 | callbacks->toggle_changed(&h3270,f,appres.toggle[f].value,TT_UPDATE,toggle_names[f]); | 751 | callbacks->toggle_changed(&h3270,f,appres.toggle[f].value,TT_UPDATE,toggle_names[f]); |
| 752 | } | 752 | } |
| 753 | -*/ | ||
| 754 | } | 753 | } |
| 754 | +*/ | ||
| 755 | 755 | ||
| 756 | void mcursor_set(H3270 *session,LIB3270_CURSOR m) | 756 | void mcursor_set(H3270 *session,LIB3270_CURSOR m) |
| 757 | { | 757 | { |
| @@ -0,0 +1,93 @@ | @@ -0,0 +1,93 @@ | ||
| 1 | +/* | ||
| 2 | + * "Software pw3270, desenvolvido com base nos códigos fontes do WC3270 e X3270 | ||
| 3 | + * (Paul Mattes Paul.Mattes@usa.net), de emulação de terminal 3270 para acesso a | ||
| 4 | + * aplicativos mainframe. Registro no INPI sob o nome G3270. | ||
| 5 | + * | ||
| 6 | + * Copyright (C) <2008> <Banco do Brasil S.A.> | ||
| 7 | + * | ||
| 8 | + * Este programa é software livre. Você pode redistribuí-lo e/ou modificá-lo sob | ||
| 9 | + * os termos da GPL v.2 - Licença Pública Geral GNU, conforme publicado pela | ||
| 10 | + * Free Software Foundation. | ||
| 11 | + * | ||
| 12 | + * Este programa é distribuído na expectativa de ser útil, mas SEM QUALQUER | ||
| 13 | + * GARANTIA; sem mesmo a garantia implícita de COMERCIALIZAÇÃO ou de ADEQUAÇÃO | ||
| 14 | + * A QUALQUER PROPÓSITO EM PARTICULAR. Consulte a Licença Pública Geral GNU para | ||
| 15 | + * obter mais detalhes. | ||
| 16 | + * | ||
| 17 | + * Você deve ter recebido uma cópia da Licença Pública Geral GNU junto com este | ||
| 18 | + * programa; se não, escreva para a Free Software Foundation, Inc., 59 Temple | ||
| 19 | + * Place, Suite 330, Boston, MA, 02111-1307, USA | ||
| 20 | + * | ||
| 21 | + * Este programa está nomeado como selection.c e possui - linhas de código. | ||
| 22 | + * | ||
| 23 | + * Contatos: | ||
| 24 | + * | ||
| 25 | + * perry.werneck@gmail.com (Alexandre Perry de Souza Werneck) | ||
| 26 | + * erico.mendonca@gmail.com (Erico Mascarenhas Mendonça) | ||
| 27 | + * | ||
| 28 | + */ | ||
| 29 | + | ||
| 30 | + #include "globals.h" | ||
| 31 | + #include "ctlr.h" | ||
| 32 | + #include <lib3270.h> | ||
| 33 | + #include <lib3270/session.h> | ||
| 34 | + #include <lib3270/selection.h> | ||
| 35 | + | ||
| 36 | +/*--[ Implement ]------------------------------------------------------------------------------------*/ | ||
| 37 | + | ||
| 38 | +LIB3270_EXPORT void lib3270_clear_selection(H3270 *session) | ||
| 39 | +{ | ||
| 40 | + int a; | ||
| 41 | + | ||
| 42 | + session->selected.begin = -1; | ||
| 43 | + session->selected.end = -1; | ||
| 44 | + | ||
| 45 | + for(a = 0; a < session->rows*session->cols; a++) | ||
| 46 | + { | ||
| 47 | + unsigned short attr = ea_buf[a].attr; | ||
| 48 | + | ||
| 49 | + if(ea_buf[a].attr & LIB3270_ATTR_SELECTED) | ||
| 50 | + { | ||
| 51 | + ea_buf[a].attr &= ~LIB3270_ATTR_SELECTED; | ||
| 52 | + if(session->update) | ||
| 53 | + session->update(session,a,ea_buf[a].chr,ea_buf[a].attr,a == session->cursor_addr); | ||
| 54 | + } | ||
| 55 | + } | ||
| 56 | +} | ||
| 57 | + | ||
| 58 | +LIB3270_EXPORT void lib3270_select_to(H3270 *session, int baddr) | ||
| 59 | +{ | ||
| 60 | + CHECK_SESSION_HANDLE(session); | ||
| 61 | + | ||
| 62 | + if(session->selected.begin < 0) | ||
| 63 | + session->selected.begin = session->selected.end = session->cursor_addr; | ||
| 64 | + | ||
| 65 | + if(baddr > session->cursor_addr) | ||
| 66 | + { | ||
| 67 | + session->selected.begin = session->cursor_addr; | ||
| 68 | + session->selected.end = baddr; | ||
| 69 | + } | ||
| 70 | + else | ||
| 71 | + { | ||
| 72 | + session->selected.begin = baddr; | ||
| 73 | + session->selected.end = session->cursor_addr; | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + // Update screen contents | ||
| 77 | + for(baddr = 0; baddr < session->rows*session->cols; baddr++) | ||
| 78 | + { | ||
| 79 | + unsigned short attr = ea_buf[baddr].attr; | ||
| 80 | + | ||
| 81 | + if(baddr >= session->selected.begin && baddr <= session->selected.end) | ||
| 82 | + attr |= LIB3270_ATTR_SELECTED; | ||
| 83 | + else | ||
| 84 | + attr &= ~LIB3270_ATTR_SELECTED; | ||
| 85 | + | ||
| 86 | + if(attr != ea_buf[baddr].attr && session->update) | ||
| 87 | + { | ||
| 88 | + ea_buf[baddr].attr = attr; | ||
| 89 | + session->update(session,baddr,ea_buf[baddr].chr,attr,baddr == session->cursor_addr); | ||
| 90 | + } | ||
| 91 | + } | ||
| 92 | +} | ||
| 93 | + |