rjb 1.5.8 → 1.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2786fa639546b77fac490cfd59ce4b41d52ecb65a45365f73b4e56676f5fef5f
4
- data.tar.gz: 97c3c18969a236cb79ea8eadb885245e7e43b99561c878f25bd5da50e2f3433b
3
+ metadata.gz: 06eaf84ad81cb13f6ae41403c49a861410021b6dc805442325736721a4de2267
4
+ data.tar.gz: 5b5dfe96970ee79488679d1c9f7e617bd0a4d5155b452f5a60ad408cfa34401d
5
5
  SHA512:
6
- metadata.gz: c336cae68daa9e4839313bb9f8136d28cbda6cb2e65b921b9e79452b84268ea0e75110841fdbd3947d09602694f480f4d4140ec433dc39fb07cb77f093daaf12
7
- data.tar.gz: 70af9504c3bda50cfca5cae4eb0d30910557557b71e5ededddadc7324e215cc7f1fd301eeb3d46885d19f8cbc241491d332b32df6de4fdfaca5b8903f22982b7
6
+ metadata.gz: 411554c897ddef118a5e6cff0a83fcfe7b4b1b7ff938b41d4f97ac3ba84bc5a6f925f46feaba7fc23a9d7e482238eacf1d475a850074536a54638c0dcd0e873f
7
+ data.tar.gz: 657db969c323fdfe224fe451c8dafbdf4b0525f8855a1043bd898e3f94f02b9428bdcbc821b5b2ae038876aecb68c1fd6cc5b3f85adb0fe59fbeb766d543c428
data/ChangeLog CHANGED
@@ -1,3 +1,40 @@
1
+ Sun Feb 7 2021 arton
2
+ * ext/extconf.rb
3
+ check javac and javah version
4
+ * ext/rjb.c
5
+ RJB_VERSION -> 1.6.3
6
+ Sat Aug 1 2020 arton
7
+ * ext/rjb.c
8
+ RJB_VERSION -> 1.6.2
9
+ * ext/load.c
10
+ support OpenJDK directory structure (without jre)
11
+ * lib/rjb.rb
12
+ change copyright notice
13
+ Wed Jul 17 2019 arton
14
+ * ext/rjb.c
15
+ RJB_VERSION -> 1.6.1
16
+ * lib/rjb.rb
17
+ java_methods and methods return symbol
18
+ implements respond_to? for Java methods
19
+ * ext/rbjexception.c
20
+ delegate to JavaProxy for respond_to? (except for to_str and exception)
21
+ * test/test.rb
22
+ change java_methods test to adjust above change
23
+ add respond_to? test
24
+ Thu Jul 11 2019 arton
25
+ * ext/rjb.c
26
+ RJB_VERSION -> 1.6.0
27
+ * ext/riconv.c
28
+ encode/decode between utf-8 and cesu-8 if char was greater than \uffff
29
+ Sun Feb 17 2019 lamby / arton
30
+ * ext/rjb.c
31
+ RJB_VERSION -> 1.5.9
32
+ * ext/depend.erb
33
+ it set javah line by ERB
34
+ * ext/extconf.rb
35
+ change javah to javac -h if it does not exist
36
+ * ext/depend
37
+ replaced by depend.erb
1
38
  Thu Jan 17 2019 arton
2
39
  * ext/rjbexception.c
3
40
  restore method_missing for the exception class
data/README.md ADDED
@@ -0,0 +1,65 @@
1
+ # Rjb is Ruby-Java bridge using Java Native Interface.
2
+
3
+ The [Ruby Kaigi 2010](http://www.slideshare.net/artonx/j-ruby-kaigi-2010)
4
+ Presentation on `Rjb`.
5
+
6
+ A short [introduction](https://www.artonx.org/collabo/backyard/?RubyJavaBridge)
7
+ in English.
8
+
9
+ Some [examples](https://www.artonx.org/collabo/backyard/?RjbQandA) in
10
+ Japanese, but the source code is clear for everybody.
11
+
12
+ # How to install
13
+
14
+ You need to install Java2 sdk, and setup `JAVA_HOME` enviromental
15
+ varible except for OS X. I assume that OS X's `JAVA_HOME` is reported
16
+ by calling `/usr/libexec/java_home`.
17
+
18
+ This done please proceed with:
19
+
20
+ ``` bash
21
+ ruby setup.rb config
22
+ ruby setup.rb setup
23
+ ```
24
+
25
+ ``` bash
26
+ # (in Unix)
27
+ sudo ruby setup.rb install
28
+ ```
29
+
30
+ or
31
+
32
+ ``` bash
33
+ # (in win32)
34
+ ruby setup.rb install
35
+ ```
36
+
37
+ # How to test
38
+
39
+ On Windows based machines:
40
+
41
+ ``` bash
42
+ cd test
43
+ ruby test.rb
44
+ ```
45
+
46
+ On Unix based machines plese see `test/readme.unix`. You need to set
47
+ `LD_LIBRARY_PATH` environmental variable to run `rjb`.
48
+
49
+ # Notice for opening non-ASCII 7bit filename
50
+
51
+ If you'll plan to open the non-ascii character named file by Java
52
+ class through Rjb, it may require to set LC_ALL environment variable
53
+ in you sciprt.
54
+
55
+ For example in Rails, set above line in `production.rb` as your environment:
56
+
57
+ ``` bash
58
+ ENV['LC_ALL'] = 'en_us.utf8' # or ja_JP.utf8 etc.
59
+ ```
60
+
61
+ cf: http://bugs.sun.com/view_bug.do?bug_id=4733494
62
+ (Thanks Paul for this information).
63
+
64
+ # Contact
65
+ artonx@yahoo.co.jp
@@ -3,7 +3,7 @@ rjb.o : rjb.c jp_co_infoseek_hp_arton_rjb_RBridge.h riconv.h rjb.h
3
3
  rjbexception.o : rjbexception.c jp_co_infoseek_hp_arton_rjb_RBridge.h riconv.h rjb.h
4
4
  load.o : load.c jp_co_infoseek_hp_arton_rjb_RBridge.h
5
5
  jp_co_infoseek_hp_arton_rjb_RBridge.h : jniwrap.h ../data/rjb/jp/co/infoseek/hp/arton/rjb/RBridge.class
6
- javah -classpath ../data/rjb jp.co.infoseek.hp.arton.rjb.RBridge
6
+ <%= javah %>
7
7
  ../data/rjb/jp/co/infoseek/hp/arton/rjb/RBridge.class : RBridge.java
8
8
  mkdir -p ../data/rjb/jp/co/infoseek/hp/arton/rjb
9
9
  javac -d ../data/rjb RBridge.java
data/ext/extconf.h CHANGED
@@ -4,5 +4,5 @@
4
4
  #define HAVE_NL_LANGINFO 1
5
5
  #define HAVE_SETLOCALE 1
6
6
  #define HAVE_GETENV 1
7
- #define RJB_RUBY_VERSION_CODE 260
7
+ #define RJB_RUBY_VERSION_CODE 300
8
8
  #endif
data/ext/extconf.rb CHANGED
@@ -4,6 +4,7 @@
4
4
  # $Date: $
5
5
  #----------------------------------
6
6
  require 'mkmf'
7
+ require 'erb'
7
8
 
8
9
  class Path
9
10
 
@@ -74,4 +75,22 @@ when /mswin32/
74
75
  when /cygwin/, /mingw/
75
76
  $defs << '-DNONAMELESSUNION'
76
77
  end
78
+
79
+ JAVAH_COMMAND = 'javac -h . -classpath ../data/rjb RBridge.java'.freeze
80
+
81
+ if find_executable('javah')
82
+ cversion = (`javac -version` =~ /\d+\.\d+\.\d+/ ) ? $& : nil
83
+ hversion = (`javah -version` =~ /\d+\.\d+\.\d+/ ) ? $& : nil
84
+ if cversion == hversion
85
+ javah = 'javah -classpath ../data/rjb jp.co.infoseek.hp.arton.rjb.RBridge'
86
+ else
87
+ $stderr.puts "warning: javac and javah version unmatch => javah: #{hversion}, javac: #{cversion}"
88
+ javah = JAVAH_COMMAND
89
+ end
90
+ else
91
+ javah = JAVAH_COMMAND
92
+ end
93
+ File.open('depend', 'w') do |fout|
94
+ fout.write ERB.new(IO::read('depend.erb')).result
95
+ end
77
96
  create_rjb_makefile
data/ext/load.c CHANGED
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Rjb - Ruby <-> Java Bridge
3
- * Copyright(c) 2004,2005,2006,2009,2010,2011 arton
3
+ * Copyright(c) 2004,2005,2006,2009,2010,2011,2020 arton
4
4
  *
5
5
  * This library is free software; you can redistribute it and/or
6
6
  * modify it under the terms of the GNU Lesser General Public
@@ -38,9 +38,11 @@
38
38
  #if defined(_WIN32) || defined(__CYGWIN__)
39
39
  #if defined(__CYGWIN__)
40
40
  #define JVMDLL "%s/jre/bin/%s/jvm.dll"
41
+ #define OPENJDK_JVMDLL "%s/bin/%s/jvm.dll"
41
42
  #define DIRSEPARATOR '/'
42
43
  #else
43
44
  #define JVMDLL "%s\\jre\\bin\\%s\\jvm.dll"
45
+ #define OPENJDK_JVMDLL "%s\\bin\\%s\\jvm.dll"
44
46
  #define DIRSEPARATOR '\\'
45
47
  #if defined(_WIN64)
46
48
  #undef JVM_TYPE
@@ -61,6 +63,7 @@
61
63
  #define JVM_TYPE "j9vm"
62
64
  #elif defined(__hpux)
63
65
  #define JVMDLL "%s/jre/lib/%s/%s/libjvm.sl"
66
+ #define OPENJDK_JVMDLL "%s/lib/%s/libjvm.sl"
64
67
  #define ARCH "PA_RISC"
65
68
  #undef JVM_TYPE
66
69
  #define JVM_TYPE "server"
@@ -88,6 +91,7 @@
88
91
  #include <sys/systeminfo.h>
89
92
  #endif
90
93
  #define JVMDLL "%s/jre/lib/%s/%s/libjvm.so"
94
+ #define OPENJDK_JVMDLL "%s/lib/%s/libjvm.so"
91
95
  #define DIRSEPARATOR '/'
92
96
  #define CLASSPATH_SEP ':'
93
97
  #endif
@@ -123,12 +127,20 @@ static int open_jvm(char* libpath)
123
127
  size_t i;
124
128
  int state;
125
129
 
130
+ if (rb_funcall(rb_cFile, rb_intern("exist?"), 1, rb_str_new2(libpath)) == RUBY_Qfalse)
131
+ {
132
+ if (RTEST(ruby_verbose))
133
+ {
134
+ fprintf(stderr, "Rjb::load try to find but not exist %s\n", libpath);
135
+ }
136
+ return 0;
137
+ }
126
138
  #if defined(RUBINIUS)
127
139
  i = 1;
128
140
  #else
129
141
  i = 0;
130
142
  #endif
131
- for (; i < COUNTOF(DLLibs); i++)
143
+ for (; i < COUNTOF(DLLibs); i++)
132
144
  {
133
145
  state = 0;
134
146
  rb_protect(safe_require, rb_str_new2(DLLibs[i]), &state);
@@ -137,7 +149,7 @@ static int open_jvm(char* libpath)
137
149
  {
138
150
  if (i > 0)
139
151
  {
140
- rb_raise(rb_eRuntimeError, "Constants DL and Fiddle is not defined.");
152
+ rb_raise(rb_eRuntimeError, "Constants DL or Fiddle is not defined.");
141
153
  return 0;
142
154
  }
143
155
  }
@@ -163,8 +175,8 @@ static int open_jvm(char* libpath)
163
175
  }
164
176
  /* get function pointers of JNI */
165
177
  #if RJB_RUBY_VERSION_CODE < 190
166
- getdefaultjavavminitargsfunc = rb_funcall(rb_funcall(rb_funcall(jvmdll, rb_intern("[]"), 2, rb_str_new2(GETDEFAULTJVMINITARGS), rb_str_new2("IP")), rb_intern("to_ptr"), 0), rb_intern("to_i"), 0);
167
- createjavavmfunc = rb_funcall(rb_funcall(rb_funcall(jvmdll, rb_intern("[]"), 2, rb_str_new2(CREATEJVM), rb_str_new2("IPPP")), rb_intern("to_ptr"), 0), rb_intern("to_i"), 0);
178
+ getdefaultjavavminitargsfunc = rb_funcall(rb_funcall(rb_funcall(jvmdll, rb_intern("[]"), 2, rb_str_new2(GETDEFAULTJVMINITARGS), rb_str_new2("IP")), rb_intern("to_ptr"), 0), rb_intern("to_i"), 0);
179
+ createjavavmfunc = rb_funcall(rb_funcall(rb_funcall(jvmdll, rb_intern("[]"), 2, rb_str_new2(CREATEJVM), rb_str_new2("IPPP")), rb_intern("to_ptr"), 0), rb_intern("to_i"), 0);
168
180
  #else
169
181
  getdefaultjavavminitargsfunc = rb_funcall(jvmdll, rb_intern("[]"), 1, rb_str_new2(GETDEFAULTJVMINITARGS));
170
182
  createjavavmfunc = rb_funcall(jvmdll, rb_intern("[]"), 1, rb_str_new2(CREATEJVM));
@@ -184,6 +196,7 @@ static int file_exist(const char* dir, const char* file)
184
196
 
185
197
  /*
186
198
  * not completed, only valid under some circumstances.
199
+ * load priority: OpenJDK -> SunJDK
187
200
  */
188
201
  static int load_jvm(const char* jvmtype)
189
202
  {
@@ -236,26 +249,37 @@ static int load_jvm(const char* jvmtype)
236
249
  *(p + strlen(p) - 1) = '\0';
237
250
  jh = p;
238
251
  }
239
- #endif
252
+ #endif
240
253
  java_home = ALLOCA_N(char, strlen(jh) + 1);
241
254
  strcpy(java_home, jh);
242
255
  if (*(java_home + strlen(jh) - 1) == DIRSEPARATOR)
243
256
  {
244
257
  *(java_home + strlen(jh) - 1) = '\0';
245
258
  }
259
+ #if defined(__APPLE__) && defined(__MACH__)
260
+ libpath = ALLOCA_N(char, sizeof(JVMDLL) + strlen(java_home) + 1);
261
+ sprintf(libpath, JVMDLL, java_home);
262
+ return open_jvm(libpath);
263
+ #else
246
264
  #if defined(_WIN32) || defined(__CYGWIN__)
247
265
  libpath = ALLOCA_N(char, sizeof(JVMDLL) + strlen(java_home)
248
266
  + strlen(jvmtype) + 1);
249
- sprintf(libpath, JVMDLL, java_home, jvmtype);
250
- #elif defined(__APPLE__) && defined(__MACH__)
251
- libpath = ALLOCA_N(char, sizeof(JVMDLL) + strlen(java_home) + 1);
252
- sprintf(libpath, JVMDLL, java_home);
253
267
  #else /* not Windows / MAC OS-X */
254
268
  libpath = ALLOCA_N(char, sizeof(JVMDLL) + strlen(java_home)
255
- + strlen(ARCH) + strlen(jvmtype) + 1);
269
+ + strlen(ARCH) + strlen(jvmtype) + 1);
270
+ #endif
271
+ sprintf(libpath, OPENJDK_JVMDLL, java_home, jvmtype);
272
+ if (open_jvm(libpath))
273
+ {
274
+ return 1;
275
+ }
276
+ #if defined(_WIN32) || defined(__CYGWIN__)
277
+ return 0;
278
+ #else /* not Windows / MAC OS-X */
256
279
  sprintf(libpath, JVMDLL, java_home, ARCH, jvmtype);
257
280
  #endif
258
281
  return open_jvm(libpath);
282
+ #endif /* __APPLE__ and __MACH */
259
283
  }
260
284
 
261
285
  static int load_bridge(JNIEnv* jenv)
@@ -269,7 +293,7 @@ static int load_bridge(JNIEnv* jenv)
269
293
  VALUE v = rb_const_get(rb_cObject, rb_intern("RjbConf"));
270
294
  v = rb_const_get(v, rb_intern("BRIDGE_FILE"));
271
295
  #else
272
- VALUE v = rb_const_get_at(rb_const_get(rb_cObject, rb_intern("RjbConf")),
296
+ VALUE v = rb_const_get_at(rb_const_get(rb_cObject, rb_intern("RjbConf")),
273
297
  rb_intern("BRIDGE_FILE"));
274
298
  #endif
275
299
  bridge = StringValuePtr(v);
@@ -352,7 +376,7 @@ int rjb_create_jvm(JNIEnv** pjenv, JavaVMInitArgs* vm_args, char* userpath, VALU
352
376
  *(p + strlen(p) - 1) = '\0';
353
377
  libjvm = p;
354
378
  }
355
- #endif
379
+ #endif
356
380
  if (libjvm == NULL || !open_jvm(libjvm))
357
381
  {
358
382
  #if defined(__APPLE__) && defined(__MACH__)
@@ -370,7 +394,7 @@ int rjb_create_jvm(JNIEnv** pjenv, JavaVMInitArgs* vm_args, char* userpath, VALU
370
394
  }
371
395
  #endif
372
396
  }
373
-
397
+
374
398
  #if RJB_RUBY_VERSION_CODE < 190 && !defined(RUBINIUS)
375
399
  ruby_errinfo = Qnil;
376
400
  #else
data/ext/riconv.c CHANGED
@@ -167,6 +167,126 @@ static void check_kcode()
167
167
  objIconvR2J = objIconvJ2R = Qnil;
168
168
  }
169
169
  }
170
+ #else
171
+ VALUE cEncoding = Qnil;
172
+ VALUE encoding_utf8 = Qnil;
173
+ static void init_encoding_vars()
174
+ {
175
+ cEncoding = rb_const_get(rb_cObject, rb_intern("Encoding"));
176
+ encoding_utf8 = rb_const_get(cEncoding, rb_intern("UTF_8"));
177
+ }
178
+ static int contains_surrogate_pair(const unsigned char* p)
179
+ {
180
+ while (*p)
181
+ {
182
+ switch (*p & 0xf0)
183
+ {
184
+ case 0xf0:
185
+ return 1;
186
+ case 0xe0:
187
+ p += 3;
188
+ break;
189
+ default:
190
+ p += (*p & 0x80) ? 2 : 1;
191
+ }
192
+ }
193
+ return 0;
194
+ }
195
+ static int contains_auxchar(const unsigned char* p)
196
+ {
197
+ while (*p)
198
+ {
199
+ if (*p == 0xed)
200
+ {
201
+ #if defined(DEBUG)
202
+ printf("find %02x %02x %02x %02x %02x %02x\n", *p, *(p + 1), *(p + 2), *(p + 3), *(p + 4), *(p + 5));
203
+ #endif
204
+ return 1;
205
+ }
206
+ switch (*p & 0xe0)
207
+ {
208
+ case 0xe0:
209
+ p++;
210
+ case 0xc0:
211
+ p++;
212
+ default:
213
+ p++;
214
+ }
215
+ }
216
+ return 0;
217
+ }
218
+
219
+ static VALUE encode_to_cesu8(const unsigned char* p)
220
+ {
221
+ size_t len = strlen(p);
222
+ char* newstr = ALLOCA_N(char, len + (len + 1) / 2);
223
+ char* dest = newstr;
224
+ int sval, i;
225
+ while (*p)
226
+ {
227
+ switch (*p & 0xf0)
228
+ {
229
+ case 0xf0:
230
+ sval = *p++ & 7;
231
+ for (i = 0; i < 3; i++)
232
+ {
233
+ sval <<= 6;
234
+ sval |= (*p++ & 0x3f);
235
+ }
236
+ *dest++ = '\xed';
237
+ *dest++ = 0xa0 | (((sval >> 16) - 1) & 0x0f);
238
+ *dest++ = 0x80 | ((sval >> 10) & 0x3f);
239
+ *dest++ = '\xed';
240
+ *dest++ = 0xb0 | ((sval >> 6) & 0x0f);
241
+ *dest++ = 0x80 | (sval & 0x3f);
242
+ break;
243
+ case 0xe0:
244
+ *dest++ = *p++;
245
+ case 0xc0:
246
+ case 0xc1:
247
+ *dest++ = *p++;
248
+ default:
249
+ *dest++ = *p++;
250
+ }
251
+ }
252
+ return rb_str_new(newstr, dest - newstr);
253
+ }
254
+ static VALUE encode_to_utf8(const unsigned char* p)
255
+ {
256
+ size_t len = strlen(p);
257
+ char* newstr = ALLOCA_N(char, len);
258
+ char* dest = newstr;
259
+ int sval, i;
260
+ while (*p)
261
+ {
262
+ if (*p == 0xed)
263
+ {
264
+ char v = *(p + 1);
265
+ char w = *(p + 2);
266
+ char y = *(p + 4);
267
+ char z = *(p + 5);
268
+ p += 6;
269
+ sval = 0x10000 + ((v & 0x0f) << 16) + ((w & 0x3f) << 10) + ((y & 0x0f) << 6) + (z & 0x3f);
270
+ sval = (((v + 1) & 0x0f) << 16) + ((w & 0x3f) << 10) + ((y & 0x0f) << 6) + (z & 0x3f);
271
+ *dest++ = 0xf0 | ((sval >> 18));
272
+ *dest++ = 0x80 | ((sval >> 12) & 0x3f);
273
+ *dest++ = 0x80 | ((sval >> 6) & 0x3f);
274
+ *dest++ = 0x80 | (sval & 0x3f);
275
+ continue;
276
+ }
277
+ switch (*p & 0xe0)
278
+ {
279
+ case 0xe0:
280
+ *dest++ = *p++;
281
+ case 0xc0:
282
+ case 0xc1:
283
+ *dest++ = *p++;
284
+ default:
285
+ *dest++ = *p++;
286
+ }
287
+ }
288
+ return rb_str_new(newstr, dest - newstr);
289
+ }
170
290
  #endif
171
291
 
172
292
  #if defined(DEBUG)
@@ -177,6 +297,8 @@ static void debug_out(VALUE v)
177
297
  strlen(p), p);
178
298
  fflush(stdout);
179
299
  }
300
+ #else
301
+ #define debug_out(n)
180
302
  #endif
181
303
 
182
304
  VALUE exticonv_local_to_utf8(VALUE local_string)
@@ -192,23 +314,24 @@ VALUE exticonv_local_to_utf8(VALUE local_string)
192
314
  return local_string;
193
315
  }
194
316
  #else
195
- VALUE cEncoding, encoding, utf8;
196
- cEncoding = rb_const_get(rb_cObject, rb_intern("Encoding"));
317
+ VALUE encoding;
318
+ if (NIL_P(cEncoding))
319
+ {
320
+ init_encoding_vars();
321
+ }
197
322
  encoding = rb_funcall(local_string, rb_intern("encoding"), 0);
198
- utf8 = rb_const_get(cEncoding, rb_intern("UTF_8"));
199
- if (encoding != utf8)
323
+ if (encoding != encoding_utf8)
200
324
  {
201
- VALUE ret = rb_funcall(local_string, rb_intern("encode"), 2, utf8, encoding);
202
- #if defined(DEBUG)
325
+ VALUE ret = rb_funcall(local_string, rb_intern("encode"), 2, encoding_utf8, encoding);
203
326
  debug_out(local_string);
204
327
  debug_out(ret);
205
- #endif
206
- return ret;
328
+ local_string = ret;
207
329
  }
208
- else
330
+ if (contains_surrogate_pair(StringValuePtr(local_string)))
209
331
  {
210
- return local_string;
332
+ local_string = encode_to_cesu8(StringValuePtr(local_string));
211
333
  }
334
+ return local_string;
212
335
  #endif
213
336
  }
214
337
 
@@ -225,6 +348,14 @@ VALUE exticonv_utf8_to_local(VALUE utf8_string)
225
348
  return utf8_string;
226
349
  }
227
350
  #else
228
- return rb_funcall(utf8_string, rb_intern("force_encoding"), 1, rb_const_get(rb_cEncoding, rb_intern("UTF_8")));
351
+ if (NIL_P(cEncoding))
352
+ {
353
+ init_encoding_vars();
354
+ }
355
+ if (contains_auxchar(StringValuePtr(utf8_string)))
356
+ {
357
+ utf8_string = encode_to_utf8(StringValuePtr(utf8_string));
358
+ }
359
+ return rb_funcall(utf8_string, rb_intern("force_encoding"), 1, encoding_utf8);
229
360
  #endif
230
361
  }