Commit 111d240274a655c1edb1f986b5ee9394deb2c7ec
1 parent
c395d1f9
Exists in
master
and in
3 other branches
Redesigning type-ahead queue.
Showing
8 changed files
with
137 additions
and
122 deletions
Show diff stats
src/include/lib3270.h
src/lib3270/Makefile.in
... | ... | @@ -354,6 +354,14 @@ else |
354 | 354 | $(BINDBG)/$(LIBNAME)@EXEEXT@ |
355 | 355 | endif |
356 | 356 | |
357 | +publish-debug: \ | |
358 | + $(BINDBG)/$(LIBNAME)@EXEEXT@ | |
359 | + | |
360 | + @rm -f ~/public-html/debug-$(LIBNAME)-@host_cpu@.zip | |
361 | + @zip \ | |
362 | + -9 -D \ | |
363 | + ~/public_html/debug-$(LIBNAME)-@host_cpu@.zip \ | |
364 | + $(BINDBG)/* | |
357 | 365 | |
358 | 366 | $(BINDBG)/$(LIBNAME)@DLLEXT@: \ |
359 | 367 | $(BINDBG)/$(LIBNAME)@DLLEXT@.@PACKAGE_MAJOR_VERSION@ | ... | ... |
src/lib3270/kybd.c
... | ... | @@ -141,6 +141,7 @@ struct ta |
141 | 141 | TA_TYPE_DEFAULT, |
142 | 142 | TA_TYPE_KEY_AID, |
143 | 143 | TA_TYPE_ACTION, |
144 | + TA_TYPE_CURSOR_MOVE, | |
144 | 145 | TA_TYPE_USER |
145 | 146 | } type; |
146 | 147 | |
... | ... | @@ -155,6 +156,13 @@ struct ta |
155 | 156 | |
156 | 157 | int (*action)(H3270 *); |
157 | 158 | |
159 | + struct | |
160 | + { | |
161 | + LIB3270_DIRECTION direction; | |
162 | + unsigned char sel; | |
163 | + int (*fn)(H3270 *, LIB3270_DIRECTION, unsigned char); | |
164 | + } move; | |
165 | + | |
158 | 166 | } args; |
159 | 167 | |
160 | 168 | }; |
... | ... | @@ -165,17 +173,17 @@ static const char dxl[] = "0123456789abcdef"; |
165 | 173 | |
166 | 174 | /* |
167 | 175 | * Check if the typeahead queue is available |
168 | - */ | |
176 | + */ /* | |
169 | 177 | static int enq_chk(H3270 *hSession) |
170 | 178 | { |
171 | - /* If no connection, forget it. */ | |
179 | + // If no connection, forget it. | |
172 | 180 | if (!lib3270_connected(hSession)) |
173 | 181 | { |
174 | 182 | lib3270_trace_event(hSession," dropped (not connected)\n"); |
175 | 183 | return -1; |
176 | 184 | } |
177 | 185 | |
178 | - /* If operator error, complain and drop it. */ | |
186 | + // If operator error, complain and drop it. | |
179 | 187 | if (hSession->kybdlock & KL_OERR_MASK) |
180 | 188 | { |
181 | 189 | lib3270_ring_bell(hSession); |
... | ... | @@ -183,7 +191,7 @@ static int enq_chk(H3270 *hSession) |
183 | 191 | return -1; |
184 | 192 | } |
185 | 193 | |
186 | - /* If scroll lock, complain and drop it. */ | |
194 | + // If scroll lock, complain and drop it. | |
187 | 195 | if (hSession->kybdlock & KL_SCROLLED) |
188 | 196 | { |
189 | 197 | lib3270_ring_bell(hSession); |
... | ... | @@ -191,7 +199,7 @@ static int enq_chk(H3270 *hSession) |
191 | 199 | return -1; |
192 | 200 | } |
193 | 201 | |
194 | - /* If typeahead disabled, complain and drop it. */ | |
202 | + // If typeahead disabled, complain and drop it. | |
195 | 203 | if (!hSession->typeahead) |
196 | 204 | { |
197 | 205 | lib3270_trace_event(hSession," dropped (no typeahead)\n"); |
... | ... | @@ -200,38 +208,87 @@ static int enq_chk(H3270 *hSession) |
200 | 208 | |
201 | 209 | return 0; |
202 | 210 | } |
211 | +*/ | |
203 | 212 | |
204 | 213 | /** |
205 | - * @brief Put a "Key-aid" on the typeahead queue | |
214 | + * @brief Create a new typeahead action. | |
215 | + * | |
216 | + * Check for typeahead availability and create a new TA structure. | |
217 | + * | |
218 | + * @return new typeahead struct or NULL if it's not available. | |
206 | 219 | */ |
207 | - static void enq_key(H3270 *session, unsigned char aid_code) | |
208 | - { | |
220 | +static struct ta * new_ta(H3270 *hSession, enum _ta_type type) | |
221 | +{ | |
209 | 222 | struct ta *ta; |
210 | 223 | |
211 | - if(enq_chk(session)) | |
212 | - return; | |
224 | + // If no connection, forget it. | |
225 | + if (!lib3270_connected(hSession)) | |
226 | + { | |
227 | + lib3270_ring_bell(hSession); | |
228 | + lib3270_trace_event(hSession,"typeahead action dropped (not connected)\n"); | |
229 | + return NULL; | |
230 | + } | |
213 | 231 | |
214 | - ta = (struct ta *) lib3270_malloc(sizeof(*ta)); | |
215 | - ta->next = (struct ta *) NULL; | |
216 | - ta->type = TA_TYPE_KEY_AID; | |
217 | - ta->args.aid_code = aid_code; | |
232 | + // If operator error, complain and drop it. | |
233 | + if (hSession->kybdlock & KL_OERR_MASK) | |
234 | + { | |
235 | + lib3270_ring_bell(hSession); | |
236 | + lib3270_trace_event(hSession,"typeahead action dropped (operator error)\n"); | |
237 | + return NULL; | |
238 | + } | |
239 | + | |
240 | + // If scroll lock, complain and drop it. | |
241 | + if (hSession->kybdlock & KL_SCROLLED) | |
242 | + { | |
243 | + lib3270_ring_bell(hSession); | |
244 | + lib3270_trace_event(hSession,"typeahead action dropped (scrolled)\n"); | |
245 | + return NULL; | |
246 | + } | |
247 | + | |
248 | + // If typeahead disabled, complain and drop it. | |
249 | + if (!hSession->typeahead) | |
250 | + { | |
251 | + lib3270_trace_event(hSession,"typeahead action dropped (no typeahead)\n"); | |
252 | + return NULL; | |
253 | + } | |
218 | 254 | |
219 | - trace("Adding key %02x on queue",(int) aid_code); | |
255 | + ta = (struct ta *) lib3270_malloc(sizeof(*ta)); | |
256 | + ta->next = (struct ta *) NULL; | |
257 | + ta->type = type; | |
220 | 258 | |
221 | - if (session->ta_head) | |
259 | + if(hSession->ta_head) | |
222 | 260 | { |
223 | - session->ta_tail->next = ta; | |
261 | + hSession->ta_tail->next = ta; | |
224 | 262 | } |
225 | 263 | else |
226 | 264 | { |
227 | - session->ta_head = ta; | |
228 | - status_typeahead(session,True); | |
265 | + hSession->ta_head = ta; | |
266 | + status_typeahead(hSession,True); | |
229 | 267 | } |
230 | - session->ta_tail = ta; | |
231 | 268 | |
232 | - lib3270_trace_event(session," Key-aid queued (kybdlock 0x%x)\n", session->kybdlock); | |
233 | - } | |
269 | + hSession->ta_tail = ta; | |
234 | 270 | |
271 | + return ta; | |
272 | +} | |
273 | + | |
274 | + | |
275 | +/** | |
276 | + * @brief Put a "Key-aid" on the typeahead queue | |
277 | + * | |
278 | + * @param hSession TN3270 Session handle. | |
279 | + * @param aid_code Key-ad code to put on typeahead. | |
280 | + */ | |
281 | + static void enq_key(H3270 *hSession, unsigned char aid_code) | |
282 | + { | |
283 | + struct ta *ta = new_ta(hSession, TA_TYPE_KEY_AID); | |
284 | + | |
285 | + if(!ta) | |
286 | + return; | |
287 | + | |
288 | + ta->args.aid_code = aid_code; | |
289 | + | |
290 | + lib3270_trace_event(hSession,"typeahead action Key-aid queued (kybdlock 0x%x)\n", hSession->kybdlock); | |
291 | + } | |
235 | 292 | |
236 | 293 | |
237 | 294 | /** |
... | ... | @@ -239,15 +296,12 @@ static int enq_chk(H3270 *hSession) |
239 | 296 | */ |
240 | 297 | static void enq_ta(H3270 *hSession, void (*fn)(H3270 *, const char *, const char *), const char *parm1, const char *parm2) |
241 | 298 | { |
242 | - struct ta *ta; | |
299 | + struct ta *ta = new_ta(hSession, TA_TYPE_DEFAULT); | |
243 | 300 | |
244 | - if(enq_chk(hSession)) | |
301 | + if(!ta) | |
245 | 302 | return; |
246 | 303 | |
247 | - ta = (struct ta *) lib3270_malloc(sizeof(*ta)); | |
248 | - ta->next = (struct ta *) NULL; | |
249 | - ta->type = TA_TYPE_DEFAULT; | |
250 | - ta->args.def.fn = fn; | |
304 | + ta->args.def.fn = fn; | |
251 | 305 | |
252 | 306 | if (parm1) |
253 | 307 | ta->args.def.parm[0] = NewString(parm1); |
... | ... | @@ -255,44 +309,17 @@ static void enq_ta(H3270 *hSession, void (*fn)(H3270 *, const char *, const char |
255 | 309 | if (parm2) |
256 | 310 | ta->args.def.parm[1] = NewString(parm2); |
257 | 311 | |
258 | - if(hSession->ta_head) | |
259 | - { | |
260 | - hSession->ta_tail->next = ta; | |
261 | - } | |
262 | - else | |
263 | - { | |
264 | - hSession->ta_head = ta; | |
265 | - status_typeahead(hSession,True); | |
266 | - } | |
267 | - hSession->ta_tail = ta; | |
268 | 312 | |
269 | - lib3270_trace_event(hSession," action queued (kybdlock 0x%x)\n", hSession->kybdlock); | |
313 | + lib3270_trace_event(hSession,"typeahead action queued (kybdlock 0x%x)\n", hSession->kybdlock); | |
270 | 314 | } |
271 | 315 | |
272 | 316 | static void enq_action(H3270 *hSession, int (*fn)(H3270 *)) |
273 | 317 | { |
274 | - struct ta *ta; | |
318 | + struct ta *ta = new_ta(hSession, TA_TYPE_ACTION); | |
275 | 319 | |
276 | - if(enq_chk(hSession)) | |
277 | - return; | |
278 | - | |
279 | - ta = (struct ta *) lib3270_malloc(sizeof(*ta)); | |
280 | - ta->next = (struct ta *) NULL; | |
281 | - ta->type = TA_TYPE_ACTION; | |
282 | 320 | ta->args.action = fn; |
283 | 321 | |
284 | - if(hSession->ta_head) | |
285 | - { | |
286 | - hSession->ta_tail->next = ta; | |
287 | - } | |
288 | - else | |
289 | - { | |
290 | - hSession->ta_head = ta; | |
291 | - status_typeahead(hSession,True); | |
292 | - } | |
293 | - hSession->ta_tail = ta; | |
294 | - | |
295 | - lib3270_trace_event(hSession," action queued (kybdlock 0x%x)\n", hSession->kybdlock); | |
322 | + lib3270_trace_event(hSession,"single action queued (kybdlock 0x%x)\n", hSession->kybdlock); | |
296 | 323 | } |
297 | 324 | |
298 | 325 | |
... | ... | @@ -320,6 +347,10 @@ int run_ta(H3270 *hSession) |
320 | 347 | lib3270_free(ta->args.def.parm[1]); |
321 | 348 | break; |
322 | 349 | |
350 | + case TA_TYPE_CURSOR_MOVE: | |
351 | + ta->args.move.fn(hSession,ta->args.move.direction,ta->args.move.sel); | |
352 | + break; | |
353 | + | |
323 | 354 | case TA_TYPE_ACTION: |
324 | 355 | ta->args.action(hSession); |
325 | 356 | break; |
... | ... | @@ -753,9 +784,11 @@ static void key_Character_wrapper(H3270 *hSession, const char *param1, const cha |
753 | 784 | (void) key_Character(hSession, code, with_ge, pasting, NULL); |
754 | 785 | } |
755 | 786 | |
756 | -/* | |
757 | - * Handle an ordinary displayable character key. Lots of stuff to handle | |
758 | - * insert-mode, protected fields and etc. | |
787 | +/** | |
788 | + * @brief Handle an ordinary displayable character key. | |
789 | + * | |
790 | + * Lots of stuff to handle insert-mode, protected fields and etc. | |
791 | + * | |
759 | 792 | */ |
760 | 793 | static Boolean key_Character(H3270 *hSession, int code, Boolean with_ge, Boolean pasting, Boolean *skipped) |
761 | 794 | { |
... | ... | @@ -1732,9 +1765,9 @@ LIB3270_EXPORT int lib3270_nextword(H3270 *hSession) |
1732 | 1765 | |
1733 | 1766 | if (hSession->kybdlock) { |
1734 | 1767 | enq_action(hSession, lib3270_nextword ); |
1735 | -// enq_ta(NextWord_action, CN, CN); | |
1736 | 1768 | return 0; |
1737 | 1769 | } |
1770 | + | |
1738 | 1771 | #if defined(X3270_ANSI) /*[*/ |
1739 | 1772 | if (IN_ANSI) |
1740 | 1773 | return 0; |
... | ... | @@ -1798,48 +1831,37 @@ LIB3270_EXPORT int lib3270_move_cursor(H3270 *hSession, LIB3270_DIRECTION dir, u |
1798 | 1831 | { |
1799 | 1832 | FAIL_IF_NOT_ONLINE(hSession); |
1800 | 1833 | |
1801 | - int cursor_addr = hSession->cursor_addr; | |
1802 | - int maxlen = hSession->cols * hSession->rows; | |
1834 | + if (hSession->kybdlock) { | |
1835 | + | |
1836 | + struct ta *ta = new_ta(hSession, TA_TYPE_CURSOR_MOVE); | |
1837 | + | |
1838 | + ta->args.move.direction = dir; | |
1839 | + ta->args.move.fn = lib3270_move_cursor; | |
1840 | + ta->args.move.sel = sel; | |
1841 | + | |
1842 | + return 0; | |
1843 | + } | |
1803 | 1844 | |
1804 | 1845 | switch(dir) |
1805 | 1846 | { |
1806 | 1847 | case LIB3270_DIR_UP: |
1807 | - | |
1808 | - if(sel && cursor_addr <= hSession->cols) | |
1809 | - return errno = EINVAL; | |
1810 | - | |
1811 | - cursor_addr -= hSession->cols; | |
1848 | + lib3270_cursor_up(hSession); | |
1812 | 1849 | break; |
1813 | 1850 | |
1814 | 1851 | case LIB3270_DIR_DOWN: |
1815 | - | |
1816 | - if(sel && cursor_addr >= (hSession->cols * (hSession->rows-1))) | |
1817 | - return errno = EINVAL; | |
1818 | - | |
1819 | - cursor_addr += hSession->cols; | |
1852 | + lib3270_cursor_down(hSession); | |
1820 | 1853 | break; |
1821 | 1854 | |
1822 | 1855 | case LIB3270_DIR_LEFT: |
1823 | - | |
1824 | - if(sel && (cursor_addr % hSession->cols) < 1) | |
1825 | - return errno = EINVAL; | |
1826 | - | |
1827 | - cursor_addr--; | |
1856 | + lib3270_cursor_left(hSession); | |
1828 | 1857 | break; |
1829 | 1858 | |
1830 | 1859 | case LIB3270_DIR_RIGHT: |
1831 | - | |
1832 | - if(sel && (cursor_addr % hSession->cols) >= (hSession->cols-1)) | |
1833 | - return errno = EINVAL; | |
1834 | - | |
1835 | - cursor_addr++; | |
1860 | + lib3270_cursor_right(hSession); | |
1836 | 1861 | break; |
1837 | 1862 | |
1838 | 1863 | case LIB3270_DIR_END: |
1839 | - | |
1840 | - cursor_addr = lib3270_get_field_end(hSession,cursor_addr); | |
1841 | - if(cursor_addr == -1) | |
1842 | - return errno = EINVAL; | |
1864 | + cursor_move(hSession,lib3270_get_field_end(hSession,hSession->cursor_addr)); | |
1843 | 1865 | break; |
1844 | 1866 | |
1845 | 1867 | default: |
... | ... | @@ -1848,31 +1870,7 @@ LIB3270_EXPORT int lib3270_move_cursor(H3270 *hSession, LIB3270_DIRECTION dir, u |
1848 | 1870 | } |
1849 | 1871 | |
1850 | 1872 | if(sel) |
1851 | - { | |
1852 | - lib3270_select_to(hSession,cursor_addr); | |
1853 | - } | |
1854 | - else | |
1855 | - { | |
1856 | - | |
1857 | - if(cursor_addr >= maxlen) | |
1858 | - { | |
1859 | - cursor_move(hSession,cursor_addr % maxlen); | |
1860 | - } | |
1861 | - else if(cursor_addr < 0) | |
1862 | - { | |
1863 | - cursor_move(hSession,cursor_addr + maxlen); | |
1864 | - } | |
1865 | - else | |
1866 | - { | |
1867 | - cursor_move(hSession,cursor_addr); | |
1868 | - } | |
1869 | - | |
1870 | - if(hSession->kybdlock && (KYBDLOCK_IS_OERR(hSession))) | |
1871 | - { | |
1872 | - status_reset(hSession); | |
1873 | - } | |
1874 | - | |
1875 | - } | |
1873 | + lib3270_select_to(hSession,hSession->cursor_addr); | |
1876 | 1874 | |
1877 | 1875 | return 0; |
1878 | 1876 | } | ... | ... |
src/lib3270/linux/connect.c
... | ... | @@ -87,7 +87,8 @@ static void net_connected(H3270 *hSession, int fd unused, LIB3270_IO_FLAG flag u |
87 | 87 | else if(err) |
88 | 88 | { |
89 | 89 | char buffer[4096]; |
90 | - snprintf(buffer,4095,_( "Can't connect to %s" ), hSession->host.current ); | |
90 | + | |
91 | + snprintf(buffer,4095,_( "Can't connect to %s" ), lib3270_get_url(hSession) ); | |
91 | 92 | |
92 | 93 | lib3270_disconnect(hSession); |
93 | 94 | lib3270_popup_dialog( | ... | ... |
src/lib3270/ssl/linux/getcrl.c
... | ... | @@ -170,7 +170,7 @@ X509_CRL * lib3270_get_X509_CRL(H3270 *hSession, SSL_ERROR_MESSAGE * message) |
170 | 170 | return NULL; |
171 | 171 | } |
172 | 172 | |
173 | - trace_ssl(hSession, "crl=%s",consturl); | |
173 | + trace_ssl(hSession, "crl=%s\n",consturl); | |
174 | 174 | |
175 | 175 | if(strncasecmp(consturl,"file://",7) == 0) |
176 | 176 | { | ... | ... |
src/lib3270/ssl/windows/getcrl.c
... | ... | @@ -130,7 +130,7 @@ X509_CRL * lib3270_get_X509_CRL(H3270 *hSession, SSL_ERROR_MESSAGE * message) |
130 | 130 | return NULL; |
131 | 131 | } |
132 | 132 | |
133 | - trace_ssl(hSession, "crl=%s",consturl); | |
133 | + trace_ssl(hSession, "crl=%s\n",consturl); | |
134 | 134 | |
135 | 135 | if(strncasecmp(consturl,"file://",7) == 0) |
136 | 136 | { |
... | ... | @@ -185,6 +185,9 @@ X509_CRL * lib3270_get_X509_CRL(H3270 *hSession, SSL_ERROR_MESSAGE * message) |
185 | 185 | return NULL; |
186 | 186 | } |
187 | 187 | |
188 | + debug("Tamanho da resposta: %u", (unsigned int) crl_data->length); | |
189 | + debug("Resposta:\n-------------------------------------------\n%s\n-------------------------------------------\n",crl_data->contents); | |
190 | + | |
188 | 191 | char *ct = NULL; |
189 | 192 | res = curl_easy_getinfo(hCurl, CURLINFO_CONTENT_TYPE, &ct); |
190 | 193 | if(res != CURLE_OK) |
... | ... | @@ -192,12 +195,12 @@ X509_CRL * lib3270_get_X509_CRL(H3270 *hSession, SSL_ERROR_MESSAGE * message) |
192 | 195 | message->error = hSession->ssl.error = 0; |
193 | 196 | message->title = N_( "Security error" ); |
194 | 197 | message->text = N_( "Error loading CRL" ); |
195 | - message->description = curl_easy_strerror(res); | |
198 | + message->description = curl_easy_strerror(res); | |
196 | 199 | lib3270_write_log(hSession,"ssl","%s: %s",consturl, message->description); |
197 | 200 | return NULL; |
198 | 201 | } |
199 | 202 | |
200 | - debug("content-type: %s",ct); | |
203 | + // debug("content-type: %s",ct); | |
201 | 204 | |
202 | 205 | if(ct) |
203 | 206 | { |
... | ... | @@ -233,7 +236,6 @@ X509_CRL * lib3270_get_X509_CRL(H3270 *hSession, SSL_ERROR_MESSAGE * message) |
233 | 236 | message->error = hSession->ssl.error = ERR_get_error(); |
234 | 237 | message->title = N_( "Security error" ); |
235 | 238 | message->text = N_( "Got an invalid CRL from LDAP server" ); |
236 | - lib3270_write_log(hSession,"ssl","%s: invalid format:\n%s\n",consturl, crl_data->contents); | |
237 | 239 | return NULL; |
238 | 240 | } |
239 | 241 | data += 3; | ... | ... |
src/lib3270/testprogram/testprogram.c
... | ... | @@ -28,6 +28,8 @@ int main(int argc, char *argv[]) |
28 | 28 | h = lib3270_session_new(""); |
29 | 29 | printf("3270 session %p created\n]",h); |
30 | 30 | |
31 | + lib3270_set_url(h,NULL); | |
32 | + | |
31 | 33 | int long_index =0; |
32 | 34 | int opt; |
33 | 35 | while((opt = getopt_long(argc, argv, "C:U:", options, &long_index )) != -1) { | ... | ... |
src/lib3270/windows/connect.c
... | ... | @@ -86,7 +86,7 @@ static void net_connected(H3270 *hSession, int fd unused, LIB3270_IO_FLAG flag u |
86 | 86 | else if(err) |
87 | 87 | { |
88 | 88 | char buffer[4096]; |
89 | - snprintf(buffer,4095,_( "Can't connect to %s" ), hSession->host.current ); | |
89 | + snprintf(buffer,4095,_( "Can't connect to %s" ), lib3270_get_url(hSession) ); | |
90 | 90 | |
91 | 91 | lib3270_disconnect(hSession); |
92 | 92 | lib3270_popup_dialog( hSession, |
... | ... | @@ -175,12 +175,17 @@ LIB3270_EXPORT int lib3270_connect_url(H3270 *hSession, const char *url, int wai |
175 | 175 | struct addrinfo * result = NULL; |
176 | 176 | struct addrinfo * rp = NULL; |
177 | 177 | |
178 | + if(!(hSession->host.current && hSession->host.srvc)) | |
179 | + return errno = ENOENT; | |
180 | + | |
178 | 181 | memset(&hints,0,sizeof(hints)); |
179 | 182 | hints.ai_family = AF_UNSPEC; // Allow IPv4 or IPv6 |
180 | 183 | hints.ai_socktype = SOCK_STREAM; // Stream socket |
181 | 184 | hints.ai_flags = AI_PASSIVE; // For wildcard IP address |
182 | 185 | hints.ai_protocol = 0; // Any protocol |
183 | 186 | |
187 | + debug("%s(%s,%s)",__FUNCTION__,hSession->host.current, hSession->host.srvc); | |
188 | + | |
184 | 189 | int rc = getaddrinfo(hSession->host.current, hSession->host.srvc, &hints, &result); |
185 | 190 | if(rc != 0) |
186 | 191 | { |
... | ... | @@ -250,7 +255,7 @@ int lib3270_reconnect(H3270 *hSession, int seconds) |
250 | 255 | char buffer[4096]; |
251 | 256 | char msg[4096]; |
252 | 257 | |
253 | - snprintf(buffer,4095,_( "Can't connect to %s:%s"), hSession->host.current, hSession->host.srvc); | |
258 | + snprintf(buffer,4095,_( "Can't connect to %s"), lib3270_get_url(hSession)); | |
254 | 259 | |
255 | 260 | strncpy(msg,host.message,4095); |
256 | 261 | ... | ... |