Annotation of embedaddon/php/ext/mbstring/libmbfl/mbfl/mbfl_convert.c, revision 1.1.1.2
1.1 misho 1: /*
2: * "streamable kanji code filter and converter"
3: * Copyright (c) 1998-2002 HappySize, Inc. All rights reserved.
4: *
5: * LICENSE NOTICES
6: *
7: * This file is part of "streamable kanji code filter and converter",
8: * which is distributed under the terms of GNU Lesser General Public
9: * License (version 2) as published by the Free Software Foundation.
10: *
11: * This software is distributed in the hope that it will be useful,
12: * but WITHOUT ANY WARRANTY; without even the implied warranty of
13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14: * GNU Lesser General Public License for more details.
15: *
16: * You should have received a copy of the GNU Lesser General Public
17: * License along with "streamable kanji code filter and converter";
18: * if not, write to the Free Software Foundation, Inc., 59 Temple Place,
19: * Suite 330, Boston, MA 02111-1307 USA
20: *
21: * The author of this file:
22: *
23: */
24: /*
25: * The source code included in this files was separated from mbfilter.c
26: * by Moriyoshi Koizumi <moriyoshi@php.net> on 20 Dec 2002. The file
27: * mbfilter.c is included in this package .
28: *
29: */
30:
31: #ifdef HAVE_CONFIG_H
32: #include "config.h"
33: #endif
34:
35: #ifdef HAVE_STDDEF_H
36: #include <stddef.h>
37: #endif
38:
39: #include "mbfl_encoding.h"
40: #include "mbfl_allocators.h"
41: #include "mbfl_filter_output.h"
42: #include "mbfilter_pass.h"
43: #include "mbfilter_8bit.h"
44: #include "mbfilter_wchar.h"
45:
46: #include "filters/mbfilter_euc_cn.h"
47: #include "filters/mbfilter_hz.h"
48: #include "filters/mbfilter_euc_tw.h"
49: #include "filters/mbfilter_big5.h"
50: #include "filters/mbfilter_uhc.h"
51: #include "filters/mbfilter_euc_kr.h"
52: #include "filters/mbfilter_iso2022_kr.h"
53: #include "filters/mbfilter_sjis.h"
54: #include "filters/mbfilter_sjis_open.h"
1.1.1.2 ! misho 55: #include "filters/mbfilter_sjis_2004.h"
! 56: #include "filters/mbfilter_sjis_mobile.h"
! 57: #include "filters/mbfilter_sjis_mac.h"
1.1 misho 58: #include "filters/mbfilter_cp51932.h"
59: #include "filters/mbfilter_jis.h"
60: #include "filters/mbfilter_iso2022_jp_ms.h"
1.1.1.2 ! misho 61: #include "filters/mbfilter_iso2022jp_2004.h"
! 62: #include "filters/mbfilter_iso2022jp_mobile.h"
1.1 misho 63: #include "filters/mbfilter_euc_jp.h"
1.1.1.2 ! misho 64: #include "filters/mbfilter_euc_jp_2004.h"
1.1 misho 65: #include "filters/mbfilter_euc_jp_win.h"
1.1.1.2 ! misho 66: #include "filters/mbfilter_gb18030.h"
1.1 misho 67: #include "filters/mbfilter_ascii.h"
68: #include "filters/mbfilter_koi8r.h"
69: #include "filters/mbfilter_koi8u.h"
70: #include "filters/mbfilter_cp866.h"
71: #include "filters/mbfilter_cp932.h"
72: #include "filters/mbfilter_cp936.h"
73: #include "filters/mbfilter_cp1251.h"
74: #include "filters/mbfilter_cp1252.h"
75: #include "filters/mbfilter_cp1254.h"
76: #include "filters/mbfilter_cp5022x.h"
77: #include "filters/mbfilter_iso8859_1.h"
78: #include "filters/mbfilter_iso8859_2.h"
79: #include "filters/mbfilter_iso8859_3.h"
80: #include "filters/mbfilter_iso8859_4.h"
81: #include "filters/mbfilter_iso8859_5.h"
82: #include "filters/mbfilter_iso8859_6.h"
83: #include "filters/mbfilter_iso8859_7.h"
84: #include "filters/mbfilter_iso8859_8.h"
85: #include "filters/mbfilter_iso8859_9.h"
86: #include "filters/mbfilter_iso8859_10.h"
87: #include "filters/mbfilter_iso8859_13.h"
88: #include "filters/mbfilter_iso8859_14.h"
89: #include "filters/mbfilter_iso8859_15.h"
90: #include "filters/mbfilter_base64.h"
91: #include "filters/mbfilter_qprint.h"
92: #include "filters/mbfilter_uuencode.h"
93: #include "filters/mbfilter_7bit.h"
94: #include "filters/mbfilter_utf7.h"
95: #include "filters/mbfilter_utf7imap.h"
96: #include "filters/mbfilter_utf8.h"
1.1.1.2 ! misho 97: #include "filters/mbfilter_utf8_mobile.h"
1.1 misho 98: #include "filters/mbfilter_utf16.h"
99: #include "filters/mbfilter_utf32.h"
100: #include "filters/mbfilter_byte2.h"
101: #include "filters/mbfilter_byte4.h"
102: #include "filters/mbfilter_ucs4.h"
103: #include "filters/mbfilter_ucs2.h"
104: #include "filters/mbfilter_htmlent.h"
105: #include "filters/mbfilter_armscii8.h"
106: #include "filters/mbfilter_cp850.h"
107:
108: /* hex character table "0123456789ABCDEF" */
109: static char mbfl_hexchar_table[] = {
110: 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46
111: };
112:
113: const struct mbfl_convert_vtbl *mbfl_convert_filter_list[] = {
114: &vtbl_utf8_wchar,
115: &vtbl_wchar_utf8,
116: &vtbl_eucjp_wchar,
117: &vtbl_wchar_eucjp,
118: &vtbl_sjis_wchar,
119: &vtbl_wchar_sjis,
120: &vtbl_sjis_open_wchar,
121: &vtbl_wchar_sjis_open,
1.1.1.2 ! misho 122: &vtbl_sjis2004_wchar,
! 123: &vtbl_wchar_sjis2004,
1.1 misho 124: &vtbl_cp51932_wchar,
125: &vtbl_wchar_cp51932,
126: &vtbl_jis_wchar,
127: &vtbl_wchar_jis,
128: &vtbl_jis_ms_wchar,
129: &vtbl_wchar_jis_ms,
130: &vtbl_2022jp_wchar,
131: &vtbl_wchar_2022jp,
132: &vtbl_2022jpms_wchar,
133: &vtbl_wchar_2022jpms,
1.1.1.2 ! misho 134: &vtbl_2022jp_2004_wchar,
! 135: &vtbl_wchar_2022jp_2004,
! 136: &vtbl_2022jp_kddi_wchar,
! 137: &vtbl_wchar_2022jp_kddi,
1.1 misho 138: &vtbl_eucjpwin_wchar,
139: &vtbl_wchar_eucjpwin,
1.1.1.2 ! misho 140: &vtbl_eucjp2004_wchar,
! 141: &vtbl_wchar_eucjp2004,
1.1 misho 142: &vtbl_cp932_wchar,
143: &vtbl_wchar_cp932,
1.1.1.2 ! misho 144: &vtbl_sjis_docomo_wchar,
! 145: &vtbl_wchar_sjis_docomo,
! 146: &vtbl_sjis_kddi_wchar,
! 147: &vtbl_wchar_sjis_kddi,
! 148: &vtbl_sjis_sb_wchar,
! 149: &vtbl_wchar_sjis_sb,
! 150: &vtbl_sjis_mac_wchar,
! 151: &vtbl_wchar_sjis_mac,
! 152: &vtbl_utf8_docomo_wchar,
! 153: &vtbl_wchar_utf8_docomo,
! 154: &vtbl_utf8_kddi_a_wchar,
! 155: &vtbl_wchar_utf8_kddi_a,
! 156: &vtbl_utf8_kddi_b_wchar,
! 157: &vtbl_wchar_utf8_kddi_b,
! 158: &vtbl_utf8_sb_wchar,
! 159: &vtbl_wchar_utf8_sb,
1.1 misho 160: &vtbl_euccn_wchar,
161: &vtbl_wchar_euccn,
162: &vtbl_cp936_wchar,
163: &vtbl_wchar_cp936,
1.1.1.2 ! misho 164: &vtbl_gb18030_wchar,
! 165: &vtbl_wchar_gb18030,
1.1 misho 166: &vtbl_hz_wchar,
167: &vtbl_wchar_hz,
168: &vtbl_euctw_wchar,
169: &vtbl_wchar_euctw,
170: &vtbl_big5_wchar,
171: &vtbl_wchar_big5,
1.1.1.2 ! misho 172: &vtbl_cp950_wchar,
! 173: &vtbl_wchar_cp950,
1.1 misho 174: &vtbl_euckr_wchar,
175: &vtbl_wchar_euckr,
176: &vtbl_uhc_wchar,
177: &vtbl_wchar_uhc,
178: &vtbl_2022kr_wchar,
179: &vtbl_wchar_2022kr,
180: &vtbl_cp1251_wchar,
181: &vtbl_wchar_cp1251,
182: &vtbl_cp866_wchar,
183: &vtbl_wchar_cp866,
184: &vtbl_koi8r_wchar,
185: &vtbl_wchar_koi8r,
186: &vtbl_koi8u_wchar,
187: &vtbl_wchar_koi8u,
188: &vtbl_cp1252_wchar,
189: &vtbl_wchar_cp1252,
190: &vtbl_cp1254_wchar,
191: &vtbl_wchar_cp1254,
192: &vtbl_cp50220_wchar,
193: &vtbl_wchar_cp50220,
194: &vtbl_cp50220raw_wchar,
195: &vtbl_wchar_cp50220raw,
196: &vtbl_cp50221_wchar,
197: &vtbl_wchar_cp50221,
198: &vtbl_cp50222_wchar,
199: &vtbl_wchar_cp50222,
200: &vtbl_ascii_wchar,
201: &vtbl_wchar_ascii,
202: &vtbl_8859_1_wchar,
203: &vtbl_wchar_8859_1,
204: &vtbl_8859_2_wchar,
205: &vtbl_wchar_8859_2,
206: &vtbl_8859_3_wchar,
207: &vtbl_wchar_8859_3,
208: &vtbl_8859_4_wchar,
209: &vtbl_wchar_8859_4,
210: &vtbl_8859_5_wchar,
211: &vtbl_wchar_8859_5,
212: &vtbl_8859_6_wchar,
213: &vtbl_wchar_8859_6,
214: &vtbl_8859_7_wchar,
215: &vtbl_wchar_8859_7,
216: &vtbl_8859_8_wchar,
217: &vtbl_wchar_8859_8,
218: &vtbl_8859_9_wchar,
219: &vtbl_wchar_8859_9,
220: &vtbl_8859_10_wchar,
221: &vtbl_wchar_8859_10,
222: &vtbl_8859_13_wchar,
223: &vtbl_wchar_8859_13,
224: &vtbl_8859_14_wchar,
225: &vtbl_wchar_8859_14,
226: &vtbl_8859_15_wchar,
227: &vtbl_wchar_8859_15,
228: &vtbl_8bit_b64,
229: &vtbl_b64_8bit,
230: &vtbl_uuencode_8bit,
231: &vtbl_wchar_html,
232: &vtbl_html_wchar,
233: &vtbl_8bit_qprint,
234: &vtbl_qprint_8bit,
235: &vtbl_8bit_7bit,
236: &vtbl_7bit_8bit,
237: &vtbl_utf7_wchar,
238: &vtbl_wchar_utf7,
239: &vtbl_utf7imap_wchar,
240: &vtbl_wchar_utf7imap,
241: &vtbl_utf16_wchar,
242: &vtbl_wchar_utf16,
243: &vtbl_utf16be_wchar,
244: &vtbl_wchar_utf16be,
245: &vtbl_utf16le_wchar,
246: &vtbl_wchar_utf16le,
247: &vtbl_utf32_wchar,
248: &vtbl_wchar_utf32,
249: &vtbl_utf32be_wchar,
250: &vtbl_wchar_utf32be,
251: &vtbl_utf32le_wchar,
252: &vtbl_wchar_utf32le,
253: &vtbl_ucs4_wchar,
254: &vtbl_wchar_ucs4,
255: &vtbl_ucs4be_wchar,
256: &vtbl_wchar_ucs4be,
257: &vtbl_ucs4le_wchar,
258: &vtbl_wchar_ucs4le,
259: &vtbl_ucs2_wchar,
260: &vtbl_wchar_ucs2,
261: &vtbl_ucs2be_wchar,
262: &vtbl_wchar_ucs2be,
263: &vtbl_ucs2le_wchar,
264: &vtbl_wchar_ucs2le,
265: &vtbl_byte4be_wchar,
266: &vtbl_wchar_byte4be,
267: &vtbl_byte4le_wchar,
268: &vtbl_wchar_byte4le,
269: &vtbl_byte2be_wchar,
270: &vtbl_wchar_byte2be,
271: &vtbl_byte2le_wchar,
272: &vtbl_wchar_byte2le,
273: &vtbl_armscii8_wchar,
274: &vtbl_wchar_armscii8,
275: &vtbl_cp850_wchar,
276: &vtbl_wchar_cp850,
277: &vtbl_pass,
278: NULL
279: };
280:
281: static int
282: mbfl_convert_filter_common_init(
283: mbfl_convert_filter *filter,
284: enum mbfl_no_encoding from,
285: enum mbfl_no_encoding to,
286: const struct mbfl_convert_vtbl *vtbl,
287: int (*output_function)(int, void* ),
288: int (*flush_function)(void*),
289: void* data)
290: {
291: /* encoding structure */
292: if ((filter->from = mbfl_no2encoding(from)) == NULL) {
293: return 1;
294: }
295:
296: if ((filter->to = mbfl_no2encoding(to)) == NULL) {
297: return 1;
298: }
299:
300: if (output_function != NULL) {
301: filter->output_function = output_function;
302: } else {
303: filter->output_function = mbfl_filter_output_null;
304: }
305:
306: filter->flush_function = flush_function;
307: filter->data = data;
308: filter->illegal_mode = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR;
309: filter->illegal_substchar = 0x3f; /* '?' */
310: filter->num_illegalchar = 0;
311: filter->filter_ctor = vtbl->filter_ctor;
312: filter->filter_dtor = vtbl->filter_dtor;
313: filter->filter_function = vtbl->filter_function;
314: filter->filter_flush = vtbl->filter_flush;
315: filter->filter_copy = vtbl->filter_copy;
316:
317: (*filter->filter_ctor)(filter);
318:
319: return 0;
320: }
321:
322:
323: mbfl_convert_filter *
324: mbfl_convert_filter_new(
325: enum mbfl_no_encoding from,
326: enum mbfl_no_encoding to,
327: int (*output_function)(int, void* ),
328: int (*flush_function)(void*),
329: void* data)
330: {
331: mbfl_convert_filter * filter;
332: const struct mbfl_convert_vtbl *vtbl;
333:
334: vtbl = mbfl_convert_filter_get_vtbl(from, to);
335:
336: if (vtbl == NULL) {
337: vtbl = &vtbl_pass;
338: }
339:
340: /* allocate */
341: filter = (mbfl_convert_filter *)mbfl_malloc(sizeof(mbfl_convert_filter));
342: if (filter == NULL) {
343: return NULL;
344: }
345:
346: if (mbfl_convert_filter_common_init(filter, from, to, vtbl,
347: output_function, flush_function, data)) {
348: mbfl_free(filter);
349: return NULL;
350: }
351:
352: return filter;
353: }
354:
355: mbfl_convert_filter *
356: mbfl_convert_filter_new2(
357: const struct mbfl_convert_vtbl *vtbl,
358: int (*output_function)(int, void* ),
359: int (*flush_function)(void*),
360: void* data)
361: {
362: mbfl_convert_filter * filter;
363:
364: if (vtbl == NULL) {
365: vtbl = &vtbl_pass;
366: }
367:
368: /* allocate */
369: filter = (mbfl_convert_filter *)mbfl_malloc(sizeof(mbfl_convert_filter));
370: if (filter == NULL) {
371: return NULL;
372: }
373:
374: if (mbfl_convert_filter_common_init(filter, vtbl->from, vtbl->to, vtbl,
375: output_function, flush_function, data)) {
376: mbfl_free(filter);
377: return NULL;
378: }
379:
380: return filter;
381: }
382:
383: void
384: mbfl_convert_filter_delete(mbfl_convert_filter *filter)
385: {
386: if (filter) {
387: (*filter->filter_dtor)(filter);
388: mbfl_free((void*)filter);
389: }
390: }
391:
392: int
393: mbfl_convert_filter_feed(int c, mbfl_convert_filter *filter)
394: {
395: return (*filter->filter_function)(c, filter);
396: }
397:
398: int
399: mbfl_convert_filter_flush(mbfl_convert_filter *filter)
400: {
401: (*filter->filter_flush)(filter);
402: return (filter->flush_function ? (*filter->flush_function)(filter->data) : 0);
403: }
404:
405: void mbfl_convert_filter_reset(mbfl_convert_filter *filter,
406: enum mbfl_no_encoding from, enum mbfl_no_encoding to)
407: {
408: const struct mbfl_convert_vtbl *vtbl;
409:
410: /* destruct old filter */
411: (*filter->filter_dtor)(filter);
412:
413: vtbl = mbfl_convert_filter_get_vtbl(from, to);
414:
415: if (vtbl == NULL) {
416: vtbl = &vtbl_pass;
417: }
418:
419: mbfl_convert_filter_common_init(filter, from, to, vtbl,
420: filter->output_function, filter->flush_function, filter->data);
421: }
422:
423: void
424: mbfl_convert_filter_copy(
425: mbfl_convert_filter *src,
426: mbfl_convert_filter *dest)
427: {
428: if (src->filter_copy != NULL) {
429: src->filter_copy(src, dest);
430: return;
431: }
432:
433: *dest = *src;
434: }
435:
436: int mbfl_convert_filter_devcat(mbfl_convert_filter *filter, mbfl_memory_device *src)
437: {
438: int n;
439: unsigned char *p;
440:
441: p = src->buffer;
442: n = src->pos;
443: while (n > 0) {
444: if ((*filter->filter_function)(*p++, filter) < 0) {
445: return -1;
446: }
447: n--;
448: }
449:
450: return n;
451: }
452:
453: int mbfl_convert_filter_strcat(mbfl_convert_filter *filter, const unsigned char *p)
454: {
455: int c;
456:
457: while ((c = *p++) != '\0') {
458: if ((*filter->filter_function)(c, filter) < 0) {
459: return -1;
460: }
461: }
462:
463: return 0;
464: }
465:
466: /* illegal character output function for conv-filter */
467: int
468: mbfl_filt_conv_illegal_output(int c, mbfl_convert_filter *filter)
469: {
470: int mode_backup, ret, n, m, r;
471:
472: ret = 0;
473: mode_backup = filter->illegal_mode;
474: filter->illegal_mode = MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE;
475: switch (mode_backup) {
476: case MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR:
477: ret = (*filter->filter_function)(filter->illegal_substchar, filter);
478: break;
479: case MBFL_OUTPUTFILTER_ILLEGAL_MODE_LONG:
480: if (c >= 0) {
481: if (c < MBFL_WCSGROUP_UCS4MAX) { /* unicode */
482: ret = mbfl_convert_filter_strcat(filter, (const unsigned char *)"U+");
483: } else {
484: if (c < MBFL_WCSGROUP_WCHARMAX) {
485: m = c & ~MBFL_WCSPLANE_MASK;
486: switch (m) {
487: case MBFL_WCSPLANE_JIS0208:
488: ret = mbfl_convert_filter_strcat(filter, (const unsigned char *)"JIS+");
489: break;
490: case MBFL_WCSPLANE_JIS0212:
491: ret = mbfl_convert_filter_strcat(filter, (const unsigned char *)"JIS2+");
492: break;
1.1.1.2 ! misho 493: case MBFL_WCSPLANE_JIS0213:
! 494: ret = mbfl_convert_filter_strcat(filter, (const unsigned char *)"JIS3+");
! 495: break;
1.1 misho 496: case MBFL_WCSPLANE_WINCP932:
497: ret = mbfl_convert_filter_strcat(filter, (const unsigned char *)"W932+");
498: break;
1.1.1.2 ! misho 499: case MBFL_WCSPLANE_GB18030:
! 500: ret = mbfl_convert_filter_strcat(filter, (const unsigned char *)"GB+");
! 501: break;
1.1 misho 502: case MBFL_WCSPLANE_8859_1:
503: ret = mbfl_convert_filter_strcat(filter, (const unsigned char *)"I8859_1+");
504: break;
505: default:
506: ret = mbfl_convert_filter_strcat(filter, (const unsigned char *)"?+");
507: break;
508: }
509: c &= MBFL_WCSPLANE_MASK;
510: } else {
511: ret = mbfl_convert_filter_strcat(filter, (const unsigned char *)"BAD+");
512: c &= MBFL_WCSGROUP_MASK;
513: }
514: }
515: if (ret >= 0) {
516: m = 0;
517: r = 28;
518: while (r >= 0) {
519: n = (c >> r) & 0xf;
520: if (n || m) {
521: m = 1;
522: ret = (*filter->filter_function)(mbfl_hexchar_table[n], filter);
523: if (ret < 0) {
524: break;
525: }
526: }
527: r -= 4;
528: }
529: if (m == 0 && ret >= 0) {
530: ret = (*filter->filter_function)(mbfl_hexchar_table[0], filter);
531: }
532: }
533: }
534: break;
535: case MBFL_OUTPUTFILTER_ILLEGAL_MODE_ENTITY:
536: if (c >= 0) {
537: if (c < MBFL_WCSGROUP_UCS4MAX) { /* unicode */
538: ret = mbfl_convert_filter_strcat(filter, (const unsigned char *)"&#x");
539: if (ret < 0)
540: break;
541:
542: m = 0;
543: r = 28;
544: while (r >= 0) {
545: n = (c >> r) & 0xf;
546: if (n || m) {
547: m = 1;
548: ret = (*filter->filter_function)(mbfl_hexchar_table[n], filter);
549: if (ret < 0) {
550: break;
551: }
552: }
553: r -= 4;
554: }
555: if (ret < 0) {
556: break;
557: }
558: if (m == 0) {
559: ret = (*filter->filter_function)(mbfl_hexchar_table[0], filter);
560: }
561: ret = mbfl_convert_filter_strcat(filter, (const unsigned char *)";");
562: } else {
563: ret = (*filter->filter_function)(filter->illegal_substchar, filter);
564: }
565: }
566: break;
567: default:
568: break;
569: }
570: filter->illegal_mode = mode_backup;
571: filter->num_illegalchar++;
572:
573: return ret;
574: }
575:
576: const struct mbfl_convert_vtbl * mbfl_convert_filter_get_vtbl(enum mbfl_no_encoding from, enum mbfl_no_encoding to)
577: {
578: const struct mbfl_convert_vtbl *vtbl;
579: int i;
580:
581: if (to == mbfl_no_encoding_base64 ||
582: to == mbfl_no_encoding_qprint ||
583: to == mbfl_no_encoding_7bit) {
584: from = mbfl_no_encoding_8bit;
585: } else if (from == mbfl_no_encoding_base64 ||
586: from == mbfl_no_encoding_qprint ||
587: from == mbfl_no_encoding_uuencode) {
588: to = mbfl_no_encoding_8bit;
589: }
590:
591: i = 0;
592: while ((vtbl = mbfl_convert_filter_list[i++]) != NULL){
593: if (vtbl->from == from && vtbl->to == to) {
594: return vtbl;
595: }
596: }
597:
598: return NULL;
599: }
600:
601: /*
602: * commonly used constructor and destructor
603: */
604: void mbfl_filt_conv_common_ctor(mbfl_convert_filter *filter)
605: {
606: filter->status = 0;
607: filter->cache = 0;
608: }
609:
610: int mbfl_filt_conv_common_flush(mbfl_convert_filter *filter)
611: {
612: filter->status = 0;
613: filter->cache = 0;
614:
615: if (filter->flush_function != NULL) {
616: (*filter->flush_function)(filter->data);
617: }
618: return 0;
619: }
620:
621: void mbfl_filt_conv_common_dtor(mbfl_convert_filter *filter)
622: {
623: filter->status = 0;
624: filter->cache = 0;
625: }
626:
627:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>