1/**********************************************************************
2  big5.c -  Oniguruma (regular expression library)
3**********************************************************************/
4/*-
5 * Copyright (c) 2002-2007  K.Kosako  <sndgk393 AT ybb DOT ne DOT jp>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include "regenc.h"
31
32static const int EncLen_BIG5[] = {
33  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
34  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
35  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
36  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
37  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
38  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
39  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
40  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
41  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
42  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
43  1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
44  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
45  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
46  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
47  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
48  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1
49};
50static const int EncLen_BIG5_HKSCS[] = {
51 /* LEN  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F */
52 /* 0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
53 /* 1 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
54 /* 2 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
55 /* 3 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
56 /* 4 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
57 /* 5 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
58 /* 6 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
59 /* 7 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
60 /* 8 */ 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
61 /* 9 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
62 /* A */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
63 /* B */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
64 /* C */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
65 /* D */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
66 /* E */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
67 /* F */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
68};
69
70static const int EncLen_BIG5_UAO[] = {
71 /* LEN  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F */
72 /* 0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
73 /* 1 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
74 /* 2 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
75 /* 3 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
76 /* 4 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
77 /* 5 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
78 /* 6 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
79 /* 7 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
80 /* 8 */ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
81 /* 9 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
82 /* A */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
83 /* B */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
84 /* C */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
85 /* D */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
86 /* E */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
87 /* F */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
88};
89
90typedef enum { FAILURE = -2, ACCEPT = -1, S0 = 0, S1 } state_t;
91#define A ACCEPT
92#define F FAILURE
93static const signed char trans[][0x100] = {
94  { /* S0   0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */
95    /* 0 */ A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
96    /* 1 */ A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
97    /* 2 */ A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
98    /* 3 */ A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
99    /* 4 */ A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
100    /* 5 */ A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
101    /* 6 */ A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
102    /* 7 */ A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
103    /* 8 */ F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F,
104    /* 9 */ F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F,
105    /* a */ F, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
106    /* b */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
107    /* c */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
108    /* d */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
109    /* e */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
110    /* f */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, F
111  },
112  { /* S1   0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */
113    /* 0 */ F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F,
114    /* 1 */ F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F,
115    /* 2 */ F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F,
116    /* 3 */ F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F,
117    /* 4 */ A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
118    /* 5 */ A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
119    /* 6 */ A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
120    /* 7 */ A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, F,
121    /* 8 */ F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F,
122    /* 9 */ F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F,
123    /* a */ F, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
124    /* b */ A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
125    /* c */ A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
126    /* d */ A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
127    /* e */ A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
128    /* f */ A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, F
129  },
130  { /* S2   0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */
131    /* 0 */ A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
132    /* 1 */ A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
133    /* 2 */ A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
134    /* 3 */ A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
135    /* 4 */ A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
136    /* 5 */ A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
137    /* 6 */ A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
138    /* 7 */ A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
139    /* 8 */ F, F, F, F, F, F, F, 1, 1, 1, 1, 1, 1, 1, 1, 1,
140    /* 9 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
141    /* a */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
142    /* b */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
143    /* c */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
144    /* d */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
145    /* e */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
146    /* f */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, F
147  }
148};
149#undef A
150#undef F
151
152static int
153big5_mbc_enc_len0(const UChar* p, const UChar* e, int tridx, const int tbl[])
154{
155  int firstbyte = *p++;
156  state_t s = trans[tridx][firstbyte];
157#define RETURN(n) \
158    return s == ACCEPT ? ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(n) : \
159                         ONIGENC_CONSTRUCT_MBCLEN_INVALID()
160  if (s < 0) RETURN(1);
161  if (p == e) return ONIGENC_CONSTRUCT_MBCLEN_NEEDMORE(tbl[firstbyte]-1);
162  s = trans[s][*p++];
163  RETURN(2);
164#undef RETURN
165}
166
167static int
168big5_mbc_enc_len(const UChar* p, const UChar* e, OnigEncoding enc ARG_UNUSED)
169{
170    return big5_mbc_enc_len0(p, e, 0, EncLen_BIG5);
171}
172
173static int
174big5_hkscs_mbc_enc_len(const UChar* p, const UChar* e, OnigEncoding enc ARG_UNUSED)
175{
176    return big5_mbc_enc_len0(p, e, 2, EncLen_BIG5_HKSCS);
177}
178
179static int
180big5_uao_mbc_enc_len(const UChar* p, const UChar* e, OnigEncoding enc ARG_UNUSED)
181{
182    return big5_mbc_enc_len0(p, e, 2, EncLen_BIG5_UAO);
183}
184
185static OnigCodePoint
186big5_mbc_to_code(const UChar* p, const UChar* end, OnigEncoding enc)
187{
188  return onigenc_mbn_mbc_to_code(enc, p, end);
189}
190
191static int
192big5_code_to_mbc(OnigCodePoint code, UChar *buf, OnigEncoding enc)
193{
194  return onigenc_mb2_code_to_mbc(enc, code, buf);
195}
196
197static int
198big5_mbc_case_fold(OnigCaseFoldType flag, const UChar** pp, const UChar* end,
199                   UChar* lower, OnigEncoding enc)
200{
201  return onigenc_mbn_mbc_case_fold(enc, flag,
202                                   pp, end, lower);
203}
204
205#if 0
206static int
207big5_is_mbc_ambiguous(OnigCaseFoldType flag,
208		      const UChar** pp, const UChar* end, OnigEncoding enc)
209{
210  return onigenc_mbn_is_mbc_ambiguous(enc, flag, pp, end);
211}
212#endif
213
214static int
215big5_is_code_ctype(OnigCodePoint code, unsigned int ctype, OnigEncoding enc)
216{
217  return onigenc_mb2_is_code_ctype(enc, code, ctype);
218}
219
220static const char BIG5_CAN_BE_TRAIL_TABLE[256] = {
221  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
222  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
223  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
224  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
225  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
226  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
227  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
228  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
229  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
230  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
231  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
232  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
233  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
234  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
235  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
236  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
237};
238
239#define BIG5_HKSCS_P(enc) ((enc)->precise_mbc_enc_len == big5_hkscs_mbc_enc_len)
240#define BIG5_UAO_P(enc) ((enc)->precise_mbc_enc_len == big5_uao_mbc_enc_len)
241
242#define BIG5_ISMB_FIRST(byte)  ( \
243	BIG5_HKSCS_P(enc) ? EncLen_BIG5_HKSCS[byte] > 1 : \
244	EncLen_BIG5[byte] > 1 \
245	)
246#define BIG5_ISMB_TRAIL(byte)  BIG5_CAN_BE_TRAIL_TABLE[(byte)]
247
248static UChar*
249big5_left_adjust_char_head(const UChar* start, const UChar* s, const UChar* end, OnigEncoding enc)
250{
251  const UChar *p;
252  int len;
253
254  if (s <= start) return (UChar* )s;
255  p = s;
256
257  if (BIG5_ISMB_TRAIL(*p)) {
258    while (p > start) {
259      if (! BIG5_ISMB_FIRST(*--p)) {
260	p++;
261	break;
262      }
263    }
264  }
265  len = enclen(enc, p, end);
266  if (p + len > s) return (UChar* )p;
267  p += len;
268  return (UChar* )(p + ((s - p) & ~1));
269}
270
271static int
272big5_is_allowed_reverse_match(const UChar* s, const UChar* end ARG_UNUSED, OnigEncoding enc ARG_UNUSED)
273{
274  const UChar c = *s;
275
276  return (BIG5_ISMB_TRAIL(c) ? FALSE : TRUE);
277}
278
279/*
280 * Name: Big5  (preferred MIME name)
281 * MIBenum: 2026
282 * Source: Chinese for Taiwan Multi-byte set.
283 *         PCL Symbol Set Id: 18T
284 * Alias: csBig5
285 */
286OnigEncodingDefine(big5, BIG5) = {
287  big5_mbc_enc_len,
288  "Big5",     /* name */
289  2,          /* max enc length */
290  1,          /* min enc length */
291  onigenc_is_mbc_newline_0x0a,
292  big5_mbc_to_code,
293  onigenc_mb2_code_to_mbclen,
294  big5_code_to_mbc,
295  big5_mbc_case_fold,
296  onigenc_ascii_apply_all_case_fold,
297  onigenc_ascii_get_case_fold_codes_by_str,
298  onigenc_minimum_property_name_to_ctype,
299  big5_is_code_ctype,
300  onigenc_not_support_get_ctype_code_range,
301  big5_left_adjust_char_head,
302  big5_is_allowed_reverse_match,
303  0,
304  ONIGENC_FLAG_NONE,
305};
306
307/*
308 * Name: CP950
309 * Source: http://msdn.microsoft.com/en-us/goglobal/cc305155.aspx
310 */
311ENC_REPLICATE("CP950", "Big5")
312
313/*
314 * Name: Big5-HKSCS
315 * MIBenum: 2101
316 * Source: http://www.iana.org/assignments/charset-reg/Big5-HKSCS
317 * Source: http://www.ogcio.gov.hk/ccli/eng/hkscs/mapping_table_2008.html
318 * Alias: None
319 */
320OnigEncodingDefine(big5_hkscs, BIG5_HKSCS) = {
321  big5_hkscs_mbc_enc_len,
322  "Big5-HKSCS",     /* name */
323  2,          /* max enc length */
324  1,          /* min enc length */
325  onigenc_is_mbc_newline_0x0a,
326  big5_mbc_to_code,
327  onigenc_mb2_code_to_mbclen,
328  big5_code_to_mbc,
329  big5_mbc_case_fold,
330  onigenc_ascii_apply_all_case_fold,
331  onigenc_ascii_get_case_fold_codes_by_str,
332  onigenc_minimum_property_name_to_ctype,
333  big5_is_code_ctype,
334  onigenc_not_support_get_ctype_code_range,
335  big5_left_adjust_char_head,
336  big5_is_allowed_reverse_match,
337  0,
338  ONIGENC_FLAG_NONE,
339};
340ENC_ALIAS("Big5-HKSCS:2008", "Big5-HKSCS")
341
342/*
343 * Name: CP951
344 * Source: http://www.microsoft.com/hk/hkscs/default.aspx
345 * Source: http://www.microsoft.com/downloads/en/details.aspx?FamilyID=0e6f5ac8-7baa-4571-b8e8-78b3b776afd7&DisplayLang=en
346 * Source: http://blogs.msdn.com/b/shawnste/archive/2007/03/12/cp-951-hkscs.aspx
347 */
348ENC_REPLICATE("CP951", "Big5-HKSCS")
349
350/*
351 * Name: Big5-UAO [NOT registered by IANA!]
352 * Source: http://moztw.org/docs/big5/table/big5_2003-b2u.txt
353 */
354OnigEncodingDefine(big5_uao, BIG5_UAO) = {
355  big5_uao_mbc_enc_len,
356  "Big5-UAO",     /* name */
357  2,          /* max enc length */
358  1,          /* min enc length */
359  onigenc_is_mbc_newline_0x0a,
360  big5_mbc_to_code,
361  onigenc_mb2_code_to_mbclen,
362  big5_code_to_mbc,
363  big5_mbc_case_fold,
364  onigenc_ascii_apply_all_case_fold,
365  onigenc_ascii_get_case_fold_codes_by_str,
366  onigenc_minimum_property_name_to_ctype,
367  big5_is_code_ctype,
368  onigenc_not_support_get_ctype_code_range,
369  big5_left_adjust_char_head,
370  big5_is_allowed_reverse_match,
371  0,
372  ONIGENC_FLAG_NONE,
373};
374