// utf-8 utility string functions
//
// Copyright (c) 2019-2023 Dario Deledda. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module utf8

// Utility functions

// len return the length as number of unicode chars from a string
pub fn len(s string) int {
	if s.len == 0 {
		return 0
	}

	mut count := 0
	mut index := 0

	for {
		ch_len := utf8_char_len(s[index])
		index += ch_len
		count++
		if index >= s.len {
			break
		}
	}
	return count
}

// get_uchar convert a unicode glyph in string[index] into a int unicode char
pub fn get_uchar(s string, index int) int {
	mut res := 0
	mut ch_len := 0
	if s.len > 0 {
		ch_len = utf8_char_len(s[index])

		if ch_len == 1 {
			return u16(s[index])
		}
		if ch_len > 1 && ch_len < 5 {
			mut lword := 0
			for i := 0; i < ch_len; i++ {
				lword = int(u32(lword) << 8 | u32(s[index + i]))
			}

			// 2 byte utf-8
			// byte format: 110xxxxx 10xxxxxx
			//
			if ch_len == 2 {
				res = (lword & 0x1f00) >> 2 | (lword & 0x3f)
			}
			// 3 byte utf-8
			// byte format: 1110xxxx 10xxxxxx 10xxxxxx
			//
			else if ch_len == 3 {
				res = (lword & 0x0f0000) >> 4 | (lword & 0x3f00) >> 2 | (lword & 0x3f)
			}
			// 4 byte utf-8
			// byte format: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
			//
			else if ch_len == 4 {
				res = ((lword & 0x07000000) >> 6) | ((lword & 0x003f0000) >> 4) | ((lword & 0x00003F00) >> 2) | (lword & 0x0000003f)
			}
		}
	}
	return res
}

// raw_index - get the raw character from the string by the given index value.
// example: utf8.raw_index('我是V Lang', 1) => '是'
pub fn raw_index(s string, index int) string {
	mut r := []rune{}

	for i := 0; i < s.len; i++ {
		if r.len - 1 == index {
			break
		}

		b := s[i]
		ch_len := ((0xe5000000 >> ((b >> 3) & 0x1e)) & 3)

		r << if ch_len > 0 {
			i += ch_len
			rune(get_uchar(s, i - ch_len))
		} else {
			rune(b)
		}
	}

	return r[index].str()
}

// reverse - returns a reversed string.
// example: utf8.reverse('你好世界hello world') => 'dlrow olleh界世好你'.
pub fn reverse(s string) string {
	len_s := len(s)
	if len_s == 0 || len_s == 1 {
		return s.clone()
	}
	mut str_array := []string{}
	for i in 0 .. len_s {
		str_array << raw_index(s, i)
	}
	str_array = str_array.reverse()
	return str_array.join('')
}

// Conversion functions

// to_upper return an uppercase string from a string
pub fn to_upper(s string) string {
	return convert_case(s, true)
}

// to_lower return an lowercase string from a string
pub fn to_lower(s string) string {
	return convert_case(s, false)
}

// Punctuation functions
//
// The "western" function search on a small table, that is quicker than
// the global unicode table search. **Use only for western chars**.

// Western

// is_punct return true if the string[index] byte is the start of a unicode western punctuation
pub fn is_punct(s string, index int) bool {
	return is_uchar_punct(get_uchar(s, index))
}

// is_control return true if the rune is control code
pub fn is_control(r rune) bool {
	// control codes are all below 0xff
	if r > max_latin_1 {
		return false
	}
	return props[u8(r)] == 1
}

// is_letter returns true if the rune is unicode letter or in unicode category L
pub fn is_letter(r rune) bool {
	if (r >= `a` && r <= `z`) || (r >= `A` && r <= `Z`) {
		return true
	} else if r <= max_latin_1 {
		return props[u8(r)] & p_l_mask != 0
	}
	return is_excluding_latin(letter_table, r)
}

// is_space returns true if the rune is character in unicode category Z with property white space or the following character set:
// ```
// `\t`, `\n`, `\v`, `\f`, `\r`, ` `, 0x85 (NEL), 0xA0 (NBSP)
// ```
pub fn is_space(r rune) bool {
	if r <= max_latin_1 {
		match r {
			`\t`, `\n`, `\v`, `\f`, `\r`, ` `, 0x85, 0xA0 {
				return true
			}
			else {
				return false
			}
		}
	}
	return is_excluding_latin(white_space_table, r)
}

// is_number returns true if the rune is unicode number or in unicode category N
pub fn is_number(r rune) bool {
	if r <= max_latin_1 {
		return props[u8(r)] & p_n != 0
	}
	return is_excluding_latin(number_table, r)
}

// is_uchar_punct return true if the input unicode is a western unicode punctuation
pub fn is_uchar_punct(uchar int) bool {
	return find_punct_in_table(uchar, utf8.unicode_punct_western) != 0
}

// Global

// is_global_punct return true if the string[index] byte of is the start of a global unicode punctuation
pub fn is_global_punct(s string, index int) bool {
	return is_uchar_global_punct(get_uchar(s, index))
}

// is_uchar_global_punct return true if the input unicode is a global unicode punctuation
pub fn is_uchar_global_punct(uchar int) bool {
	return find_punct_in_table(uchar, utf8.unicode_punct) != 0
}

// Private functions

// utf8_to_lower raw utf-8 to_lower function
fn utf8_to_lower(in_cp int) int {
	mut cp := in_cp
	if (0x0041 <= cp && 0x005a >= cp) || (0x00c0 <= cp && 0x00d6 >= cp)
		|| (0x00d8 <= cp && 0x00de >= cp) || (0x0391 <= cp && 0x03a1 >= cp)
		|| (0x03a3 <= cp && 0x03ab >= cp) || (0x0410 <= cp && 0x042f >= cp) {
		cp += 32
	} else if 0x0400 <= cp && 0x040f >= cp {
		cp += 80
	} else if (0x0100 <= cp && 0x012f >= cp) || (0x0132 <= cp && 0x0137 >= cp)
		|| (0x014a <= cp && 0x0177 >= cp) || (0x0182 <= cp && 0x0185 >= cp)
		|| (0x01a0 <= cp && 0x01a5 >= cp) || (0x01de <= cp && 0x01ef >= cp)
		|| (0x01f8 <= cp && 0x021f >= cp) || (0x0222 <= cp && 0x0233 >= cp)
		|| (0x0246 <= cp && 0x024f >= cp) || (0x03d8 <= cp && 0x03ef >= cp)
		|| (0x0460 <= cp && 0x0481 >= cp) || (0x048a <= cp && 0x04ff >= cp) {
		cp |= 0x1
	} else if (0x0139 <= cp && 0x0148 >= cp) || (0x0179 <= cp && 0x017e >= cp)
		|| (0x01af <= cp && 0x01b0 >= cp) || (0x01b3 <= cp && 0x01b6 >= cp)
		|| (0x01cd <= cp && 0x01dc >= cp) {
		cp += 1
		cp &= ~0x1
	} else if (0x0531 <= cp && 0x0556 >= cp) || (0x10A0 <= cp && 0x10C5 >= cp) {
		// ARMENIAN or GEORGIAN
		cp += 0x30
	} else if ((0x1E00 <= cp && 0x1E94 >= cp) || (0x1EA0 <= cp && 0x1EF8 >= cp)) && cp & 1 == 0 {
		// LATIN CAPITAL LETTER
		cp += 1
	} else if 0x24B6 <= cp && 0x24CF >= cp {
		// CIRCLED LATIN
		cp += 0x1a
	} else if 0xFF21 <= cp && 0xFF3A >= cp {
		// FULLWIDTH LATIN CAPITAL
		cp += 0x19
	} else if (0x1F08 <= cp && 0x1F0F >= cp) || (0x1F18 <= cp && 0x1F1D >= cp)
		|| (0x1F28 <= cp && 0x1F2F >= cp) || (0x1F38 <= cp && 0x1F3F >= cp)
		|| (0x1F48 <= cp && 0x1F4D >= cp) || (0x1F68 <= cp && 0x1F6F >= cp)
		|| (0x1F88 <= cp && 0x1F8F >= cp) || (0x1F98 <= cp && 0x1F9F >= cp)
		|| (0x1FA8 <= cp && 0x1FAF >= cp) {
		// GREEK
		cp -= 8
	} else {
		match cp {
			0x0178 { cp = 0x00ff }
			0x0243 { cp = 0x0180 }
			0x018e { cp = 0x01dd }
			0x023d { cp = 0x019a }
			0x0220 { cp = 0x019e }
			0x01b7 { cp = 0x0292 }
			0x01c4 { cp = 0x01c6 }
			0x01c7 { cp = 0x01c9 }
			0x01ca { cp = 0x01cc }
			0x01f1 { cp = 0x01f3 }
			0x01f7 { cp = 0x01bf }
			0x0187 { cp = 0x0188 }
			0x018b { cp = 0x018c }
			0x0191 { cp = 0x0192 }
			0x0198 { cp = 0x0199 }
			0x01a7 { cp = 0x01a8 }
			0x01ac { cp = 0x01ad }
			0x01af { cp = 0x01b0 }
			0x01b8 { cp = 0x01b9 }
			0x01bc { cp = 0x01bd }
			0x01f4 { cp = 0x01f5 }
			0x023b { cp = 0x023c }
			0x0241 { cp = 0x0242 }
			0x03fd { cp = 0x037b }
			0x03fe { cp = 0x037c }
			0x03ff { cp = 0x037d }
			0x037f { cp = 0x03f3 }
			0x0386 { cp = 0x03ac }
			0x0388 { cp = 0x03ad }
			0x0389 { cp = 0x03ae }
			0x038a { cp = 0x03af }
			0x038c { cp = 0x03cc }
			0x038e { cp = 0x03cd }
			0x038f { cp = 0x03ce }
			0x0370 { cp = 0x0371 }
			0x0372 { cp = 0x0373 }
			0x0376 { cp = 0x0377 }
			0x03f4 { cp = 0x03b8 }
			0x03cf { cp = 0x03d7 }
			0x03f9 { cp = 0x03f2 }
			0x03f7 { cp = 0x03f8 }
			0x03fa { cp = 0x03fb }
			// GREEK
			0x1F59 { cp = 0x1F51 }
			0x1F5B { cp = 0x1F53 }
			0x1F5D { cp = 0x1F55 }
			0x1F5F { cp = 0x1F57 }
			0x1FB8 { cp = 0x1FB0 }
			0x1FB9 { cp = 0x1FB1 }
			0x1FD8 { cp = 0x1FD0 }
			0x1FD9 { cp = 0x1FD1 }
			0x1FE8 { cp = 0x1FE0 }
			0x1FE9 { cp = 0x1FE1 }
			else {}
		}
	}

	return cp
}

// utf8_to_upper raw utf-8 to_upper function
fn utf8_to_upper(in_cp int) int {
	mut cp := in_cp
	if (0x0061 <= cp && 0x007a >= cp) || (0x00e0 <= cp && 0x00f6 >= cp)
		|| (0x00f8 <= cp && 0x00fe >= cp) || (0x03b1 <= cp && 0x03c1 >= cp)
		|| (0x03c3 <= cp && 0x03cb >= cp) || (0x0430 <= cp && 0x044f >= cp) {
		cp -= 32
	} else if 0x0450 <= cp && 0x045f >= cp {
		cp -= 80
	} else if (0x0100 <= cp && 0x012f >= cp) || (0x0132 <= cp && 0x0137 >= cp)
		|| (0x014a <= cp && 0x0177 >= cp) || (0x0182 <= cp && 0x0185 >= cp)
		|| (0x01a0 <= cp && 0x01a5 >= cp) || (0x01de <= cp && 0x01ef >= cp)
		|| (0x01f8 <= cp && 0x021f >= cp) || (0x0222 <= cp && 0x0233 >= cp)
		|| (0x0246 <= cp && 0x024f >= cp) || (0x03d8 <= cp && 0x03ef >= cp)
		|| (0x0460 <= cp && 0x0481 >= cp) || (0x048a <= cp && 0x04ff >= cp) {
		cp &= ~0x1
	} else if (0x0139 <= cp && 0x0148 >= cp) || (0x0179 <= cp && 0x017e >= cp)
		|| (0x01af <= cp && 0x01b0 >= cp) || (0x01b3 <= cp && 0x01b6 >= cp)
		|| (0x01cd <= cp && 0x01dc >= cp) {
		cp -= 1
		cp |= 0x1
	} else if (0x0561 <= cp && 0x0586 >= cp) || (0x10D0 <= cp && 0x10F5 >= cp) {
		// ARMENIAN or GEORGIAN
		cp -= 0x30
	} else if ((0x1E01 <= cp && 0x1E95 >= cp) || (0x1EA1 <= cp && 0x1EF9 >= cp)) && cp & 1 == 1 {
		// LATIN CAPITAL LETTER
		cp -= 1
	} else if 0x24D0 <= cp && 0x24E9 >= cp {
		// CIRCLED LATIN
		cp -= 0x1a
	} else if 0xFF41 <= cp && 0xFF5A >= cp {
		// FULLWIDTH LATIN CAPITAL
		cp -= 0x19
	} else if (0x1F00 <= cp && 0x1F07 >= cp) || (0x1F10 <= cp && 0x1F15 >= cp)
		|| (0x1F20 <= cp && 0x1F27 >= cp) || (0x1F30 <= cp && 0x1F37 >= cp)
		|| (0x1F40 <= cp && 0x1F45 >= cp) || (0x1F60 <= cp && 0x1F67 >= cp)
		|| (0x1F80 <= cp && 0x1F87 >= cp) || (0x1F90 <= cp && 0x1F97 >= cp)
		|| (0x1FA0 <= cp && 0x1FA7 >= cp) {
		// GREEK
		cp += 8
	} else {
		match cp {
			0x00ff { cp = 0x0178 }
			0x0180 { cp = 0x0243 }
			0x01dd { cp = 0x018e }
			0x019a { cp = 0x023d }
			0x019e { cp = 0x0220 }
			0x0292 { cp = 0x01b7 }
			0x01c6 { cp = 0x01c4 }
			0x01c9 { cp = 0x01c7 }
			0x01cc { cp = 0x01ca }
			0x01f3 { cp = 0x01f1 }
			0x01bf { cp = 0x01f7 }
			0x0188 { cp = 0x0187 }
			0x018c { cp = 0x018b }
			0x0192 { cp = 0x0191 }
			0x0199 { cp = 0x0198 }
			0x01a8 { cp = 0x01a7 }
			0x01ad { cp = 0x01ac }
			0x01b0 { cp = 0x01af }
			0x01b9 { cp = 0x01b8 }
			0x01bd { cp = 0x01bc }
			0x01f5 { cp = 0x01f4 }
			0x023c { cp = 0x023b }
			0x0242 { cp = 0x0241 }
			0x037b { cp = 0x03fd }
			0x037c { cp = 0x03fe }
			0x037d { cp = 0x03ff }
			0x03f3 { cp = 0x037f }
			0x03ac { cp = 0x0386 }
			0x03ad { cp = 0x0388 }
			0x03ae { cp = 0x0389 }
			0x03af { cp = 0x038a }
			0x03cc { cp = 0x038c }
			0x03cd { cp = 0x038e }
			0x03ce { cp = 0x038f }
			0x0371 { cp = 0x0370 }
			0x0373 { cp = 0x0372 }
			0x0377 { cp = 0x0376 }
			0x03d1 { cp = 0x0398 }
			0x03d7 { cp = 0x03cf }
			0x03f2 { cp = 0x03f9 }
			0x03f8 { cp = 0x03f7 }
			0x03fb { cp = 0x03fa }
			// GREEK
			0x1F51 { cp = 0x1F59 }
			0x1F53 { cp = 0x1F5B }
			0x1F55 { cp = 0x1F5D }
			0x1F57 { cp = 0x1F5F }
			0x1FB0 { cp = 0x1FB8 }
			0x1FB1 { cp = 0x1FB9 }
			0x1FD0 { cp = 0x1FD8 }
			0x1FD1 { cp = 0x1FD9 }
			0x1FE0 { cp = 0x1FE8 }
			0x1FE1 { cp = 0x1FE9 }
			else {}
		}
	}

	return cp
}

// convert_case converts letter cases
//
// if upper_flag == true  then convert lowercase ==> uppercase
// if upper_flag == false then convert uppercase ==> lowercase
[direct_array_access]
fn convert_case(s string, upper_flag bool) string {
	mut index := 0
	mut tab_char := 0
	mut str_res := unsafe { malloc_noscan(s.len + 1) }

	for {
		ch_len := utf8_char_len(s[index])

		if ch_len == 1 {
			if upper_flag == true {
				unsafe {
					// Subtract 0x20 from ASCII lowercase to convert to uppercase.
					c := s[index]
					str_res[index] = if c >= 0x61 && c <= 0x7a { c & 0xdf } else { c }
				}
			} else {
				unsafe {
					// Add 0x20 to ASCII uppercase to convert to lowercase.
					c := s[index]
					str_res[index] = if c >= 0x41 && c <= 0x5a { c | 0x20 } else { c }
				}
			}
		} else if ch_len > 1 && ch_len < 5 {
			mut lword := 0

			for i := 0; i < ch_len; i++ {
				lword = int(u32(lword) << 8 | u32(s[index + i]))
			}

			// println("#${index} ($lword)")

			mut res := 0

			// 2 byte utf-8
			// byte format: 110xxxxx 10xxxxxx
			//
			if ch_len == 2 {
				res = (lword & 0x1f00) >> 2 | (lword & 0x3f)
			}
			// 3 byte utf-8
			// byte format: 1110xxxx 10xxxxxx 10xxxxxx
			//
			else if ch_len == 3 {
				res = (lword & 0x0f0000) >> 4 | (lword & 0x3f00) >> 2 | (lword & 0x3f)
			}
			// 4 byte utf-8
			// byte format: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
			//
			else if ch_len == 4 {
				res = ((lword & 0x07000000) >> 6) | ((lword & 0x003f0000) >> 4) | ((lword & 0x00003F00) >> 2) | (lword & 0x0000003f)
			}

			// println("res: ${res.hex():8}")

			if upper_flag == false {
				tab_char = utf8_to_lower(res)
			} else {
				tab_char = utf8_to_upper(res)
			}

			if ch_len == 2 {
				ch0 := u8((tab_char >> 6) & 0x1f) | 0xc0 // 110x xxxx
				ch1 := u8((tab_char >> 0) & 0x3f) | 0x80 // 10xx xxxx
				// C.printf("[%02x%02x] \n",ch0,ch1)

				unsafe {
					str_res[index + 0] = ch0
					str_res[index + 1] = ch1
				}
				///***************************************************************
				//  BUG: doesn't compile, workaround use shitf to right of 0 bit
				///***************************************************************
				// str_res[index + 1 ] = u8( tab_char & 0xbf )	// 1011 1111
			} else if ch_len == 3 {
				ch0 := u8((tab_char >> 12) & 0x0f) | 0xe0 // 1110 xxxx
				ch1 := u8((tab_char >> 6) & 0x3f) | 0x80 // 10xx xxxx
				ch2 := u8((tab_char >> 0) & 0x3f) | 0x80 // 10xx xxxx
				// C.printf("[%02x%02x%02x] \n",ch0,ch1,ch2)

				unsafe {
					str_res[index + 0] = ch0
					str_res[index + 1] = ch1
					str_res[index + 2] = ch2
				}
			}
			// TODO: write if needed
			else if ch_len == 4 {
				// place holder!!
				// at the present time simply copy the utf8 char
				for i in 0 .. ch_len {
					unsafe {
						str_res[index + i] = s[index + i]
					}
				}
			}
		} else {
			// other cases, just copy the string
			for i in 0 .. ch_len {
				unsafe {
					str_res[index + i] = s[index + i]
				}
			}
		}

		index += ch_len

		// we are done, exit the loop
		if index >= s.len {
			break
		}
	}

	// for c compatibility set the ending 0
	unsafe {
		str_res[index] = 0
		return tos(str_res, s.len)
	}
}

// find_punct_in_table looks for valid punctuation in table
[direct_array_access]
fn find_punct_in_table(in_code int, in_table []int) int {
	// uses simple binary search

	mut first_index := 0
	mut last_index := (in_table.len)
	mut index := 0
	mut x := 0

	for {
		index = (first_index + last_index) >> 1
		x = in_table[index]
		// C.printf("(%d..%d) index:%d base[%08x]==>[%08x]\n",first_index,last_index,index,in_code,x)

		if x == in_code {
			return index
		} else if x > in_code {
			last_index = index
		} else {
			first_index = index
		}

		if (last_index - first_index) <= 1 {
			break
		}
	}

	return 0
}

// Unicode punctuation chars
//
// source: http://www.unicode.org/faq/punctuation_symbols.html

const (
	// Western punctuation mark
	// Character	Name	Browser	Image
	unicode_punct_western = [
		0x0021, // EXCLAMATION MARK !
		0x0022, // QUOTATION MARK "
		0x0027, // APOSTROPHE '
		0x002A, // ASTERISK *
		0x002C, // COMMA ,
		0x002E, // FULL STOP	.
		0x002F, // SOLIDUS /
		0x003A, // COLON :
		0x003B, // SEMICOLON	;
		0x003F, // QUESTION MARK ?
		0x00A1, // INVERTED EXCLAMATION MARK ¡
		0x00A7, // SECTION SIGN	§
		0x00B6, // PILCROW SIGN	¶
		0x00B7, // MIDDLE DOT ·
		0x00BF, // INVERTED QUESTION MARK ¿
		0x037E, // GREEK QUESTION MARK ;
		0x0387, // GREEK ANO TELEIA ·
		0x055A, // ARMENIAN APOSTROPHE ՚
		0x055B, // ARMENIAN EMPHASIS MARK ՛
		0x055C, // ARMENIAN EXCLAMATION MARK ՜
		0x055D, // ARMENIAN COMMA	՝
		0x055E, // ARMENIAN QUESTION MARK ՞
		0x055F, // ARMENIAN ABBREVIATION MARK	՟
		0x0589, // ARMENIAN FULL STOP	։
		0x05C0, // HEBREW PUNCTUATION PASEQ	׀
		0x05C3, // HEBREW PUNCTUATION SOF PASUQ	׃
		0x05C6, // HEBREW PUNCTUATION NUN HAFUKHA	׆
		0x05F3, // HEBREW PUNCTUATION GERESH	׳
		0x05F4, // HEBREW PUNCTUATION GERSHAYIM	״
	]

	// Unicode Characters in the 'Punctuation, Other' Category
	// Character	Name	Browser	Image
	unicode_punct         = [
		0x0021, // EXCLAMATION MARK	!
		0x0022, // QUOTATION MARK	"
		0x0023, // NUMBER SIGN	#
		0x0025, // PERCENT SIGN	%
		0x0026, // AMPERSAND	&
		0x0027, // APOSTROPHE	'
		0x002A, // ASTERISK	*
		0x002C, // COMMA	,
		0x002E, // FULL STOP	.
		0x002F, // SOLIDUS	/
		0x003A, // COLON	:
		0x003B, // SEMICOLON	;
		0x003F, // QUESTION MARK	?
		0x0040, // COMMERCIAL AT	@
		0x005C, // REVERSE SOLIDUS	\
		0x00A1, // INVERTED EXCLAMATION MARK	¡
		0x00A7, // SECTION SIGN	§
		0x00B6, // PILCROW SIGN	¶
		0x00B7, // MIDDLE DOT	·
		0x00BF, // INVERTED QUESTION MARK	¿
		0x037E, // GREEK QUESTION MARK	;
		0x0387, // GREEK ANO TELEIA	·
		0x055A, // ARMENIAN APOSTROPHE	՚
		0x055B, // ARMENIAN EMPHASIS MARK	՛
		0x055C, // ARMENIAN EXCLAMATION MARK	՜
		0x055D, // ARMENIAN COMMA	՝
		0x055E, // ARMENIAN QUESTION MARK	՞
		0x055F, // ARMENIAN ABBREVIATION MARK	՟
		0x0589, // ARMENIAN FULL STOP	։
		0x05C0, // HEBREW PUNCTUATION PASEQ	׀
		0x05C3, // HEBREW PUNCTUATION SOF PASUQ	׃
		0x05C6, // HEBREW PUNCTUATION NUN HAFUKHA	׆
		0x05F3, // HEBREW PUNCTUATION GERESH	׳
		0x05F4, // HEBREW PUNCTUATION GERSHAYIM	״
		0x0609, // ARABIC-INDIC PER MILLE SIGN	؉
		0x060A, // ARABIC-INDIC PER TEN THOUSAND SIGN	؊
		0x060C, // ARABIC COMMA	،
		0x060D, // ARABIC DATE SEPARATOR	؍
		0x061B, // ARABIC SEMICOLON	؛
		0x061E, // ARABIC TRIPLE DOT PUNCTUATION MARK	؞
		0x061F, // ARABIC QUESTION MARK	؟
		0x066A, // ARABIC PERCENT SIGN	٪
		0x066B, // ARABIC DECIMAL SEPARATOR	٫
		0x066C, // ARABIC THOUSANDS SEPARATOR	٬
		0x066D, // ARABIC FIVE POINTED STAR	٭
		0x06D4, // ARABIC FULL STOP	۔
		0x0700, // SYRIAC END OF PARAGRAPH	܀
		0x0701, // SYRIAC SUPRALINEAR FULL STOP	܁
		0x0702, // SYRIAC SUBLINEAR FULL STOP	܂
		0x0703, // SYRIAC SUPRALINEAR COLON	܃
		0x0704, // SYRIAC SUBLINEAR COLON	܄
		0x0705, // SYRIAC HORIZONTAL COLON	܅
		0x0706, // SYRIAC COLON SKEWED LEFT	܆
		0x0707, // SYRIAC COLON SKEWED RIGHT	܇
		0x0708, // SYRIAC SUPRALINEAR COLON SKEWED LEFT	܈
		0x0709, // SYRIAC SUBLINEAR COLON SKEWED RIGHT	܉
		0x070A, // SYRIAC CONTRACTION	܊
		0x070B, // SYRIAC HARKLEAN OBELUS	܋
		0x070C, // SYRIAC HARKLEAN METOBELUS	܌
		0x070D, // SYRIAC HARKLEAN ASTERISCUS	܍
		0x07F7, // NKO SYMBOL GBAKURUNEN	߷
		0x07F8, // NKO COMMA	߸
		0x07F9, // NKO EXCLAMATION MARK	߹
		0x0830, // SAMARITAN PUNCTUATION NEQUDAA	࠰
		0x0831, // SAMARITAN PUNCTUATION AFSAAQ	࠱
		0x0832, // SAMARITAN PUNCTUATION ANGED	࠲
		0x0833, // SAMARITAN PUNCTUATION BAU	࠳
		0x0834, // SAMARITAN PUNCTUATION ATMAAU	࠴
		0x0835, // SAMARITAN PUNCTUATION SHIYYAALAA	࠵
		0x0836, // SAMARITAN ABBREVIATION MARK	࠶
		0x0837, // SAMARITAN PUNCTUATION MELODIC QITSA	࠷
		0x0838, // SAMARITAN PUNCTUATION ZIQAA	࠸
		0x0839, // SAMARITAN PUNCTUATION QITSA	࠹
		0x083A, // SAMARITAN PUNCTUATION ZAEF	࠺
		0x083B, // SAMARITAN PUNCTUATION TURU	࠻
		0x083C, // SAMARITAN PUNCTUATION ARKAANU	࠼
		0x083D, // SAMARITAN PUNCTUATION SOF MASHFAAT	࠽
		0x083E, // SAMARITAN PUNCTUATION ANNAAU	࠾
		0x085E, // MANDAIC PUNCTUATION	࡞
		0x0964, // DEVANAGARI DANDA	।
		0x0965, // DEVANAGARI DOUBLE DANDA	॥
		0x0970, // DEVANAGARI ABBREVIATION SIGN	॰
		0x09FD, // BENGALI ABBREVIATION SIGN	৽
		0x0A76, // GURMUKHI ABBREVIATION SIGN	੶
		0x0AF0, // GUJARATI ABBREVIATION SIGN	૰
		0x0C77, // TELUGU SIGN SIDDHAM	౷
		0x0C84, // KANNADA SIGN SIDDHAM	಄
		0x0DF4, // SINHALA PUNCTUATION KUNDDALIYA	෴
		0x0E4F, // THAI CHARACTER FONGMAN	๏
		0x0E5A, // THAI CHARACTER ANGKHANKHU	๚
		0x0E5B, // THAI CHARACTER KHOMUT	๛
		0x0F04, // TIBETAN MARK INITIAL YIG MGO MDUN MA	༄
		0x0F05, // TIBETAN MARK CLOSING YIG MGO SGAB MA	༅
		0x0F06, // TIBETAN MARK CARET YIG MGO PHUR SHAD MA	༆
		0x0F07, // TIBETAN MARK YIG MGO TSHEG SHAD MA	༇
		0x0F08, // TIBETAN MARK SBRUL SHAD	༈
		0x0F09, // TIBETAN MARK BSKUR YIG MGO	༉
		0x0F0A, // TIBETAN MARK BKA- SHOG YIG MGO	༊
		0x0F0B, // TIBETAN MARK INTERSYLLABIC TSHEG	་
		0x0F0C, // TIBETAN MARK DELIMITER TSHEG BSTAR	༌
		0x0F0D, // TIBETAN MARK SHAD	།
		0x0F0E, // TIBETAN MARK NYIS SHAD	༎
		0x0F0F, // TIBETAN MARK TSHEG SHAD	༏
		0x0F10, // TIBETAN MARK NYIS TSHEG SHAD	༐
		0x0F11, // TIBETAN MARK RIN CHEN SPUNGS SHAD	༑
		0x0F12, // TIBETAN MARK RGYA GRAM SHAD	༒
		0x0F14, // TIBETAN MARK GTER TSHEG	༔
		0x0F85, // TIBETAN MARK PALUTA	྅
		0x0FD0, // TIBETAN MARK BSKA- SHOG GI MGO RGYAN	࿐
		0x0FD1, // TIBETAN MARK MNYAM YIG GI MGO RGYAN	࿑
		0x0FD2, // TIBETAN MARK NYIS TSHEG	࿒
		0x0FD3, // TIBETAN MARK INITIAL BRDA RNYING YIG MGO MDUN MA	࿓
		0x0FD4, // TIBETAN MARK CLOSING BRDA RNYING YIG MGO SGAB MA	࿔
		0x0FD9, // TIBETAN MARK LEADING MCHAN RTAGS	࿙
		0x0FDA, // TIBETAN MARK TRAILING MCHAN RTAGS	࿚
		0x104A, // MYANMAR SIGN LITTLE SECTION	၊
		0x104B, // MYANMAR SIGN SECTION	။
		0x104C, // MYANMAR SYMBOL LOCATIVE	၌
		0x104D, // MYANMAR SYMBOL COMPLETED	၍
		0x104E, // MYANMAR SYMBOL AFOREMENTIONED	၎
		0x104F, // MYANMAR SYMBOL GENITIVE	၏
		0x10FB, // GEORGIAN PARAGRAPH SEPARATOR	჻
		0x1360, // ETHIOPIC SECTION MARK	፠
		0x1361, // ETHIOPIC WORDSPACE	፡
		0x1362, // ETHIOPIC FULL STOP	።
		0x1363, // ETHIOPIC COMMA	፣
		0x1364, // ETHIOPIC SEMICOLON	፤
		0x1365, // ETHIOPIC COLON	፥
		0x1366, // ETHIOPIC PREFACE COLON	፦
		0x1367, // ETHIOPIC QUESTION MARK	፧
		0x1368, // ETHIOPIC PARAGRAPH SEPARATOR	፨
		0x166E, // CANADIAN SYLLABICS FULL STOP	᙮
		0x16EB, // RUNIC SINGLE PUNCTUATION	᛫
		0x16EC, // RUNIC MULTIPLE PUNCTUATION	᛬
		0x16ED, // RUNIC CROSS PUNCTUATION	᛭
		0x1735, // PHILIPPINE SINGLE PUNCTUATION	᜵
		0x1736, // PHILIPPINE DOUBLE PUNCTUATION	᜶
		0x17D4, // KHMER SIGN KHAN	។
		0x17D5, // KHMER SIGN BARIYOOSAN	៕
		0x17D6, // KHMER SIGN CAMNUC PII KUUH	៖
		0x17D8, // KHMER SIGN BEYYAL	៘
		0x17D9, // KHMER SIGN PHNAEK MUAN	៙
		0x17DA, // KHMER SIGN KOOMUUT	៚
		0x1800, // MONGOLIAN BIRGA	᠀
		0x1801, // MONGOLIAN ELLIPSIS	᠁
		0x1802, // MONGOLIAN COMMA	᠂
		0x1803, // MONGOLIAN FULL STOP	᠃
		0x1804, // MONGOLIAN COLON	᠄
		0x1805, // MONGOLIAN FOUR DOTS	᠅
		0x1807, // MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER	᠇
		0x1808, // MONGOLIAN MANCHU COMMA	᠈
		0x1809, // MONGOLIAN MANCHU FULL STOP	᠉
		0x180A, // MONGOLIAN NIRUGU	᠊
		0x1944, // LIMBU EXCLAMATION MARK	᥄
		0x1945, // LIMBU QUESTION MARK	᥅
		0x1A1E, // BUGINESE PALLAWA	᨞
		0x1A1F, // BUGINESE END OF SECTION	᨟
		0x1AA0, // TAI THAM SIGN WIANG	᪠
		0x1AA1, // TAI THAM SIGN WIANGWAAK	᪡
		0x1AA2, // TAI THAM SIGN SAWAN	᪢
		0x1AA3, // TAI THAM SIGN KEOW	᪣
		0x1AA4, // TAI THAM SIGN HOY	᪤
		0x1AA5, // TAI THAM SIGN DOKMAI	᪥
		0x1AA6, // TAI THAM SIGN REVERSED ROTATED RANA	᪦
		0x1AA8, // TAI THAM SIGN KAAN	᪨
		0x1AA9, // TAI THAM SIGN KAANKUU	᪩
		0x1AAA, // TAI THAM SIGN SATKAAN	᪪
		0x1AAB, // TAI THAM SIGN SATKAANKUU	᪫
		0x1AAC, // TAI THAM SIGN HANG	᪬
		0x1AAD, // TAI THAM SIGN CAANG	᪭
		0x1B5A, // BALINESE PANTI	᭚
		0x1B5B, // BALINESE PAMADA	᭛
		0x1B5C, // BALINESE WINDU	᭜
		0x1B5D, // BALINESE CARIK PAMUNGKAH	᭝
		0x1B5E, // BALINESE CARIK SIKI	᭞
		0x1B5F, // BALINESE CARIK PAREREN	᭟
		0x1B60, // BALINESE PAMENENG	᭠
		0x1BFC, // BATAK SYMBOL BINDU NA METEK	᯼
		0x1BFD, // BATAK SYMBOL BINDU PINARBORAS	᯽
		0x1BFE, // BATAK SYMBOL BINDU JUDUL	᯾
		0x1BFF, // BATAK SYMBOL BINDU PANGOLAT	᯿
		0x1C3B, // LEPCHA PUNCTUATION TA-ROL	᰻
		0x1C3C, // LEPCHA PUNCTUATION NYET THYOOM TA-ROL	᰼
		0x1C3D, // LEPCHA PUNCTUATION CER-WA	᰽
		0x1C3E, // LEPCHA PUNCTUATION TSHOOK CER-WA	᰾
		0x1C3F, // LEPCHA PUNCTUATION TSHOOK	᰿
		0x1C7E, // OL CHIKI PUNCTUATION MUCAAD	᱾
		0x1C7F, // OL CHIKI PUNCTUATION DOUBLE MUCAAD	᱿
		0x1CC0, // SUNDANESE PUNCTUATION BINDU SURYA	᳀
		0x1CC1, // SUNDANESE PUNCTUATION BINDU PANGLONG	᳁
		0x1CC2, // SUNDANESE PUNCTUATION BINDU PURNAMA	᳂
		0x1CC3, // SUNDANESE PUNCTUATION BINDU CAKRA	᳃
		0x1CC4, // SUNDANESE PUNCTUATION BINDU LEU SATANGA	᳄
		0x1CC5, // SUNDANESE PUNCTUATION BINDU KA SATANGA	᳅
		0x1CC6, // SUNDANESE PUNCTUATION BINDU DA SATANGA	᳆
		0x1CC7, // SUNDANESE PUNCTUATION BINDU BA SATANGA	᳇
		0x1CD3, // VEDIC SIGN NIHSHVASA	᳓
		0x2016, // DOUBLE VERTICAL LINE	‖
		0x2017, // DOUBLE LOW LINE	‗
		0x2020, // DAGGER	†
		0x2021, // DOUBLE DAGGER	‡
		0x2022, // BULLET	•
		0x2023, // TRIANGULAR BULLET	‣
		0x2024, // ONE DOT LEADER	․
		0x2025, // TWO DOT LEADER	‥
		0x2026, // HORIZONTAL ELLIPSIS	…
		0x2027, // HYPHENATION POINT	‧
		0x2030, // PER MILLE SIGN	‰
		0x2031, // PER TEN THOUSAND SIGN	‱
		0x2032, // PRIME	′
		0x2033, // DOUBLE PRIME	″
		0x2034, // TRIPLE PRIME	‴
		0x2035, // REVERSED PRIME	‵
		0x2036, // REVERSED DOUBLE PRIME	‶
		0x2037, // REVERSED TRIPLE PRIME	‷
		0x2038, // CARET	‸
		0x203B, // REFERENCE MARK	※
		0x203C, // DOUBLE EXCLAMATION MARK	‼
		0x203D, // INTERROBANG	‽
		0x203E, // OVERLINE	‾
		0x2041, // CARET INSERTION POINT	⁁
		0x2042, // ASTERISM	⁂
		0x2043, // HYPHEN BULLET	⁃
		0x2047, // DOUBLE QUESTION MARK	⁇
		0x2048, // QUESTION EXCLAMATION MARK	⁈
		0x2049, // EXCLAMATION QUESTION MARK	⁉
		0x204A, // TIRONIAN SIGN ET	⁊
		0x204B, // REVERSED PILCROW SIGN	⁋
		0x204C, // BLACK LEFTWARDS BULLET	⁌
		0x204D, // BLACK RIGHTWARDS BULLET	⁍
		0x204E, // LOW ASTERISK	⁎
		0x204F, // REVERSED SEMICOLON	⁏
		0x2050, // CLOSE UP	⁐
		0x2051, // TWO ASTERISKS ALIGNED VERTICALLY	⁑
		0x2053, // SWUNG DASH	⁓
		0x2055, // FLOWER PUNCTUATION MARK	⁕
		0x2056, // THREE DOT PUNCTUATION	⁖
		0x2057, // QUADRUPLE PRIME	⁗
		0x2058, // FOUR DOT PUNCTUATION	⁘
		0x2059, // FIVE DOT PUNCTUATION	⁙
		0x205A, // TWO DOT PUNCTUATION	⁚
		0x205B, // FOUR DOT MARK	⁛
		0x205C, // DOTTED CROSS	⁜
		0x205D, // TRICOLON	⁝
		0x205E, // VERTICAL FOUR DOTS	⁞
		0x2CF9, // COPTIC OLD NUBIAN FULL STOP	⳹
		0x2CFA, // COPTIC OLD NUBIAN DIRECT QUESTION MARK	⳺
		0x2CFB, // COPTIC OLD NUBIAN INDIRECT QUESTION MARK	⳻
		0x2CFC, // COPTIC OLD NUBIAN VERSE DIVIDER	⳼
		0x2CFE, // COPTIC FULL STOP	⳾
		0x2CFF, // COPTIC MORPHOLOGICAL DIVIDER	⳿
		0x2D70, // TIFINAGH SEPARATOR MARK	⵰
		0x2E00, // RIGHT ANGLE SUBSTITUTION MARKER	⸀
		0x2E01, // RIGHT ANGLE DOTTED SUBSTITUTION MARKER	⸁
		0x2E06, // RAISED INTERPOLATION MARKER	⸆
		0x2E07, // RAISED DOTTED INTERPOLATION MARKER	⸇
		0x2E08, // DOTTED TRANSPOSITION MARKER	⸈
		0x2E0B, // RAISED SQUARE	⸋
		0x2E0E, // EDITORIAL CORONIS	⸎
		0x2E0F, // PARAGRAPHOS	⸏
		0x2E10, // FORKED PARAGRAPHOS	⸐
		0x2E11, // REVERSED FORKED PARAGRAPHOS	⸑
		0x2E12, // HYPODIASTOLE	⸒
		0x2E13, // DOTTED OBELOS	⸓
		0x2E14, // DOWNWARDS ANCORA	⸔
		0x2E15, // UPWARDS ANCORA	⸕
		0x2E16, // DOTTED RIGHT-POINTING ANGLE	⸖
		0x2E18, // INVERTED INTERROBANG	⸘
		0x2E19, // PALM BRANCH	⸙
		0x2E1B, // TILDE WITH RING ABOVE	⸛
		0x2E1E, // TILDE WITH DOT ABOVE	⸞
		0x2E1F, // TILDE WITH DOT BELOW	⸟
		0x2E2A, // TWO DOTS OVER ONE DOT PUNCTUATION	⸪
		0x2E2B, // ONE DOT OVER TWO DOTS PUNCTUATION	⸫
		0x2E2C, // SQUARED FOUR DOT PUNCTUATION	⸬
		0x2E2D, // FIVE DOT MARK	⸭
		0x2E2E, // REVERSED QUESTION MARK	⸮
		0x2E30, // RING POINT	⸰
		0x2E31, // WORD SEPARATOR MIDDLE DOT	⸱
		0x2E32, // TURNED COMMA	⸲
		0x2E33, // RAISED DOT	⸳
		0x2E34, // RAISED COMMA	⸴
		0x2E35, // TURNED SEMICOLON	⸵
		0x2E36, // DAGGER WITH LEFT GUARD	⸶
		0x2E37, // DAGGER WITH RIGHT GUARD	⸷
		0x2E38, // TURNED DAGGER	⸸
		0x2E39, // TOP HALF SECTION SIGN	⸹
		0x2E3C, // STENOGRAPHIC FULL STOP	⸼
		0x2E3D, // VERTICAL SIX DOTS	⸽
		0x2E3E, // WIGGLY VERTICAL LINE	⸾
		0x2E3F, // CAPITULUM	⸿
		0x2E41, // REVERSED COMMA	⹁
		0x2E43, // DASH WITH LEFT UPTURN	⹃
		0x2E44, // DOUBLE SUSPENSION MARK	⹄
		0x2E45, // INVERTED LOW KAVYKA	⹅
		0x2E46, // INVERTED LOW KAVYKA WITH KAVYKA ABOVE	⹆
		0x2E47, // LOW KAVYKA	⹇
		0x2E48, // LOW KAVYKA WITH DOT	⹈
		0x2E49, // DOUBLE STACKED COMMA	⹉
		0x2E4A, // DOTTED SOLIDUS	⹊
		0x2E4B, // TRIPLE DAGGER	⹋
		0x2E4C, // MEDIEVAL COMMA	⹌
		0x2E4D, // PARAGRAPHUS MARK	⹍
		0x2E4E, // PUNCTUS ELEVATUS MARK	⹎
		0x2E4F, // CORNISH VERSE DIVIDER	⹏
		0x3001, // IDEOGRAPHIC COMMA	、
		0x3002, // IDEOGRAPHIC FULL STOP	。
		0x3003, // DITTO MARK	〃
		0x303D, // PART ALTERNATION MARK	〽
		0x30FB, // KATAKANA MIDDLE DOT	・
		0xA4FE, // LISU PUNCTUATION COMMA	꓾
		0xA4FF, // LISU PUNCTUATION FULL STOP	꓿
		0xA60D, // VAI COMMA	꘍
		0xA60E, // VAI FULL STOP	꘎
		0xA60F, // VAI QUESTION MARK	꘏
		0xA673, // SLAVONIC ASTERISK	꙳
		0xA67E, // CYRILLIC KAVYKA	꙾
		0xA6F2, // BAMUM NJAEMLI	꛲
		0xA6F3, // BAMUM FULL STOP	꛳
		0xA6F4, // BAMUM COLON	꛴
		0xA6F5, // BAMUM COMMA	꛵
		0xA6F6, // BAMUM SEMICOLON	꛶
		0xA6F7, // BAMUM QUESTION MARK	꛷
		0xA874, // PHAGS-PA SINGLE HEAD MARK	꡴
		0xA875, // PHAGS-PA DOUBLE HEAD MARK	꡵
		0xA876, // PHAGS-PA MARK SHAD	꡶
		0xA877, // PHAGS-PA MARK DOUBLE SHAD	꡷
		0xA8CE, // SAURASHTRA DANDA	꣎
		0xA8CF, // SAURASHTRA DOUBLE DANDA	꣏
		0xA8F8, // DEVANAGARI SIGN PUSHPIKA	꣸
		0xA8F9, // DEVANAGARI GAP FILLER	꣹
		0xA8FA, // DEVANAGARI CARET	꣺
		0xA8FC, // DEVANAGARI SIGN SIDDHAM	꣼
		0xA92E, // KAYAH LI SIGN CWI	꤮
		0xA92F, // KAYAH LI SIGN SHYA	꤯
		0xA95F, // REJANG SECTION MARK	꥟
		0xA9C1, // JAVANESE LEFT RERENGGAN	꧁
		0xA9C2, // JAVANESE RIGHT RERENGGAN	꧂
		0xA9C3, // JAVANESE PADA ANDAP	꧃
		0xA9C4, // JAVANESE PADA MADYA	꧄
		0xA9C5, // JAVANESE PADA LUHUR	꧅
		0xA9C6, // JAVANESE PADA WINDU	꧆
		0xA9C7, // JAVANESE PADA PANGKAT	꧇
		0xA9C8, // JAVANESE PADA LINGSA	꧈
		0xA9C9, // JAVANESE PADA LUNGSI	꧉
		0xA9CA, // JAVANESE PADA ADEG	꧊
		0xA9CB, // JAVANESE PADA ADEG ADEG	꧋
		0xA9CC, // JAVANESE PADA PISELEH	꧌
		0xA9CD, // JAVANESE TURNED PADA PISELEH	꧍
		0xA9DE, // JAVANESE PADA TIRTA TUMETES	꧞
		0xA9DF, // JAVANESE PADA ISEN-ISEN	꧟
		0xAA5C, // CHAM PUNCTUATION SPIRAL	꩜
		0xAA5D, // CHAM PUNCTUATION DANDA	꩝
		0xAA5E, // CHAM PUNCTUATION DOUBLE DANDA	꩞
		0xAA5F, // CHAM PUNCTUATION TRIPLE DANDA	꩟
		0xAADE, // TAI VIET SYMBOL HO HOI	꫞
		0xAADF, // TAI VIET SYMBOL KOI KOI	꫟
		0xAAF0, // MEETEI MAYEK CHEIKHAN	꫰
		0xAAF1, // MEETEI MAYEK AHANG KHUDAM	꫱
		0xABEB, // MEETEI MAYEK CHEIKHEI	꯫
		0xFE10, // PRESENTATION FORM FOR VERTICAL COMMA	︐
		0xFE11, // PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC COMMA	︑
		0xFE12, // PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC FULL STOP	︒
		0xFE13, // PRESENTATION FORM FOR VERTICAL COLON	︓
		0xFE14, // PRESENTATION FORM FOR VERTICAL SEMICOLON	︔
		0xFE15, // PRESENTATION FORM FOR VERTICAL EXCLAMATION MARK	︕
		0xFE16, // PRESENTATION FORM FOR VERTICAL QUESTION MARK	︖
		0xFE19, // PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS	︙
		0xFE30, // PRESENTATION FORM FOR VERTICAL TWO DOT LEADER	︰
		0xFE45, // SESAME DOT	﹅
		0xFE46, // WHITE SESAME DOT	﹆
		0xFE49, // DASHED OVERLINE	﹉
		0xFE4A, // CENTRELINE OVERLINE	﹊
		0xFE4B, // WAVY OVERLINE	﹋
		0xFE4C, // DOUBLE WAVY OVERLINE	﹌
		0xFE50, // SMALL COMMA	﹐
		0xFE51, // SMALL IDEOGRAPHIC COMMA	﹑
		0xFE52, // SMALL FULL STOP	﹒
		0xFE54, // SMALL SEMICOLON	﹔
		0xFE55, // SMALL COLON	﹕
		0xFE56, // SMALL QUESTION MARK	﹖
		0xFE57, // SMALL EXCLAMATION MARK	﹗
		0xFE5F, // SMALL NUMBER SIGN	﹟
		0xFE60, // SMALL AMPERSAND	﹠
		0xFE61, // SMALL ASTERISK	﹡
		0xFE68, // SMALL REVERSE SOLIDUS	﹨
		0xFE6A, // SMALL PERCENT SIGN	﹪
		0xFE6B, // SMALL COMMERCIAL AT	﹫
		0xFF01, // FULLWIDTH EXCLAMATION MARK	！
		0xFF02, // FULLWIDTH QUOTATION MARK	＂
		0xFF03, // FULLWIDTH NUMBER SIGN	＃
		0xFF05, // FULLWIDTH PERCENT SIGN	％
		0xFF06, // FULLWIDTH AMPERSAND	＆
		0xFF07, // FULLWIDTH APOSTROPHE	＇
		0xFF0A, // FULLWIDTH ASTERISK	＊
		0xFF0C, // FULLWIDTH COMMA	，
		0xFF0E, // FULLWIDTH FULL STOP	．
		0xFF0F, // FULLWIDTH SOLIDUS	／
		0xFF1A, // FULLWIDTH COLON	：
		0xFF1B, // FULLWIDTH SEMICOLON	；
		0xFF1F, // FULLWIDTH QUESTION MARK	？
		0xFF20, // FULLWIDTH COMMERCIAL AT	＠
		0xFF3C, // FULLWIDTH REVERSE SOLIDUS	＼
		0xFF61, // HALFWIDTH IDEOGRAPHIC FULL STOP	｡
		0xFF64, // HALFWIDTH IDEOGRAPHIC COMMA	､
		0xFF65, // HALFWIDTH KATAKANA MIDDLE DOT	･
		0x10100, // AEGEAN WORD SEPARATOR LINE	𐄀
		0x10101, // AEGEAN WORD SEPARATOR DOT	𐄁
		0x10102, // AEGEAN CHECK MARK	𐄂
		0x1039F, // UGARITIC WORD DIVIDER	𐎟
		0x103D0, // OLD PERSIAN WORD DIVIDER	𐏐
		0x1056F, // CAUCASIAN ALBANIAN CITATION MARK	𐕯
		0x10857, // IMPERIAL ARAMAIC SECTION SIGN	𐡗
		0x1091F, // PHOENICIAN WORD SEPARATOR	𐤟
		0x1093F, // LYDIAN TRIANGULAR MARK	𐤿
		0x10A50, // KHAROSHTHI PUNCTUATION DOT	𐩐
		0x10A51, // KHAROSHTHI PUNCTUATION SMALL CIRCLE	𐩑
		0x10A52, // KHAROSHTHI PUNCTUATION CIRCLE	𐩒
		0x10A53, // KHAROSHTHI PUNCTUATION CRESCENT BAR	𐩓
		0x10A54, // KHAROSHTHI PUNCTUATION MANGALAM	𐩔
		0x10A55, // KHAROSHTHI PUNCTUATION LOTUS	𐩕
		0x10A56, // KHAROSHTHI PUNCTUATION DANDA	𐩖
		0x10A57, // KHAROSHTHI PUNCTUATION DOUBLE DANDA	𐩗
		0x10A58, // KHAROSHTHI PUNCTUATION LINES	𐩘
		0x10A7F, // OLD SOUTH ARABIAN NUMERIC INDICATOR	𐩿
		0x10AF0, // MANICHAEAN PUNCTUATION STAR	𐫰
		0x10AF1, // MANICHAEAN PUNCTUATION FLEURON	𐫱
		0x10AF2, // MANICHAEAN PUNCTUATION DOUBLE DOT WITHIN DOT	𐫲
		0x10AF3, // MANICHAEAN PUNCTUATION DOT WITHIN DOT	𐫳
		0x10AF4, // MANICHAEAN PUNCTUATION DOT	𐫴
		0x10AF5, // MANICHAEAN PUNCTUATION TWO DOTS	𐫵
		0x10AF6, // MANICHAEAN PUNCTUATION LINE FILLER	𐫶
		0x10B39, // AVESTAN ABBREVIATION MARK	𐬹
		0x10B3A, // TINY TWO DOTS OVER ONE DOT PUNCTUATION	𐬺
		0x10B3B, // SMALL TWO DOTS OVER ONE DOT PUNCTUATION	𐬻
		0x10B3C, // LARGE TWO DOTS OVER ONE DOT PUNCTUATION	𐬼
		0x10B3D, // LARGE ONE DOT OVER TWO DOTS PUNCTUATION	𐬽
		0x10B3E, // LARGE TWO RINGS OVER ONE RING PUNCTUATION	𐬾
		0x10B3F, // LARGE ONE RING OVER TWO RINGS PUNCTUATION	𐬿
		0x10B99, // PSALTER PAHLAVI SECTION MARK	𐮙
		0x10B9A, // PSALTER PAHLAVI TURNED SECTION MARK	𐮚
		0x10B9B, // PSALTER PAHLAVI FOUR DOTS WITH CROSS	𐮛
		0x10B9C, // PSALTER PAHLAVI FOUR DOTS WITH DOT	𐮜
		0x10F55, // SOGDIAN PUNCTUATION TWO VERTICAL BARS	𐽕
		0x10F56, // SOGDIAN PUNCTUATION TWO VERTICAL BARS WITH DOTS	𐽖
		0x10F57, // SOGDIAN PUNCTUATION CIRCLE WITH DOT	𐽗
		0x10F58, // SOGDIAN PUNCTUATION TWO CIRCLES WITH DOTS	𐽘
		0x10F59, // SOGDIAN PUNCTUATION HALF CIRCLE WITH DOT	𐽙
		0x11047, // BRAHMI DANDA	𑁇
		0x11048, // BRAHMI DOUBLE DANDA	𑁈
		0x11049, // BRAHMI PUNCTUATION DOT	𑁉
		0x1104A, // BRAHMI PUNCTUATION DOUBLE DOT	𑁊
		0x1104B, // BRAHMI PUNCTUATION LINE	𑁋
		0x1104C, // BRAHMI PUNCTUATION CRESCENT BAR	𑁌
		0x1104D, // BRAHMI PUNCTUATION LOTUS	𑁍
		0x110BB, // KAITHI ABBREVIATION SIGN	𑂻
		0x110BC, // KAITHI ENUMERATION SIGN	𑂼
		0x110BE, // KAITHI SECTION MARK	𑂾
		0x110BF, // KAITHI DOUBLE SECTION MARK	𑂿
		0x110C0, // KAITHI DANDA	𑃀
		0x110C1, // KAITHI DOUBLE DANDA	𑃁
		0x11140, // CHAKMA SECTION MARK	𑅀
		0x11141, // CHAKMA DANDA	𑅁
		0x11142, // CHAKMA DOUBLE DANDA	𑅂
		0x11143, // CHAKMA QUESTION MARK	𑅃
		0x11174, // MAHAJANI ABBREVIATION SIGN	𑅴
		0x11175, // MAHAJANI SECTION MARK	𑅵
		0x111C5, // SHARADA DANDA	𑇅
		0x111C6, // SHARADA DOUBLE DANDA	𑇆
		0x111C7, // SHARADA ABBREVIATION SIGN	𑇇
		0x111C8, // SHARADA SEPARATOR	𑇈
		0x111CD, // SHARADA SUTRA MARK	𑇍
		0x111DB, // SHARADA SIGN SIDDHAM	𑇛
		0x111DD, // SHARADA CONTINUATION SIGN	𑇝
		0x111DE, // SHARADA SECTION MARK-1	𑇞
		0x111DF, // SHARADA SECTION MARK-2	𑇟
		0x11238, // KHOJKI DANDA	𑈸
		0x11239, // KHOJKI DOUBLE DANDA	𑈹
		0x1123A, // KHOJKI WORD SEPARATOR	𑈺
		0x1123B, // KHOJKI SECTION MARK	𑈻
		0x1123C, // KHOJKI DOUBLE SECTION MARK	𑈼
		0x1123D, // KHOJKI ABBREVIATION SIGN	𑈽
		0x112A9, // MULTANI SECTION MARK	𑊩
		0x1144B, // NEWA DANDA	𑑋
		0x1144C, // NEWA DOUBLE DANDA	𑑌
		0x1144D, // NEWA COMMA	𑑍
		0x1144E, // NEWA GAP FILLER	𑑎
		0x1144F, // NEWA ABBREVIATION SIGN	𑑏
		0x1145B, // NEWA PLACEHOLDER MARK	𑑛
		0x1145D, // NEWA INSERTION SIGN	𑑝
		0x114C6, // TIRHUTA ABBREVIATION SIGN	𑓆
		0x115C1, // SIDDHAM SIGN SIDDHAM	𑗁
		0x115C2, // SIDDHAM DANDA	𑗂
		0x115C3, // SIDDHAM DOUBLE DANDA	𑗃
		0x115C4, // SIDDHAM SEPARATOR DOT	𑗄
		0x115C5, // SIDDHAM SEPARATOR BAR	𑗅
		0x115C6, // SIDDHAM REPETITION MARK-1	𑗆
		0x115C7, // SIDDHAM REPETITION MARK-2	𑗇
		0x115C8, // SIDDHAM REPETITION MARK-3	𑗈
		0x115C9, // SIDDHAM END OF TEXT MARK	𑗉
		0x115CA, // SIDDHAM SECTION MARK WITH TRIDENT AND U-SHAPED ORNAMENTS	𑗊
		0x115CB, // SIDDHAM SECTION MARK WITH TRIDENT AND DOTTED CRESCENTS	𑗋
		0x115CC, // SIDDHAM SECTION MARK WITH RAYS AND DOTTED CRESCENTS	𑗌
		0x115CD, // SIDDHAM SECTION MARK WITH RAYS AND DOTTED DOUBLE CRESCENTS	𑗍
		0x115CE, // SIDDHAM SECTION MARK WITH RAYS AND DOTTED TRIPLE CRESCENTS	𑗎
		0x115CF, // SIDDHAM SECTION MARK DOUBLE RING	𑗏
		0x115D0, // SIDDHAM SECTION MARK DOUBLE RING WITH RAYS	𑗐
		0x115D1, // SIDDHAM SECTION MARK WITH DOUBLE CRESCENTS	𑗑
		0x115D2, // SIDDHAM SECTION MARK WITH TRIPLE CRESCENTS	𑗒
		0x115D3, // SIDDHAM SECTION MARK WITH QUADRUPLE CRESCENTS	𑗓
		0x115D4, // SIDDHAM SECTION MARK WITH SEPTUPLE CRESCENTS	𑗔
		0x115D5, // SIDDHAM SECTION MARK WITH CIRCLES AND RAYS	𑗕
		0x115D6, // SIDDHAM SECTION MARK WITH CIRCLES AND TWO ENCLOSURES	𑗖
		0x115D7, // SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES	𑗗
		0x11641, // MODI DANDA	𑙁
		0x11642, // MODI DOUBLE DANDA	𑙂
		0x11643, // MODI ABBREVIATION SIGN	𑙃
		0x11660, // MONGOLIAN BIRGA WITH ORNAMENT	𑙠
		0x11661, // MONGOLIAN ROTATED BIRGA	𑙡
		0x11662, // MONGOLIAN DOUBLE BIRGA WITH ORNAMENT	𑙢
		0x11663, // MONGOLIAN TRIPLE BIRGA WITH ORNAMENT	𑙣
		0x11664, // MONGOLIAN BIRGA WITH DOUBLE ORNAMENT	𑙤
		0x11665, // MONGOLIAN ROTATED BIRGA WITH ORNAMENT	𑙥
		0x11666, // MONGOLIAN ROTATED BIRGA WITH DOUBLE ORNAMENT	𑙦
		0x11667, // MONGOLIAN INVERTED BIRGA	𑙧
		0x11668, // MONGOLIAN INVERTED BIRGA WITH DOUBLE ORNAMENT	𑙨
		0x11669, // MONGOLIAN SWIRL BIRGA	𑙩
		0x1166A, // MONGOLIAN SWIRL BIRGA WITH ORNAMENT	𑙪
		0x1166B, // MONGOLIAN SWIRL BIRGA WITH DOUBLE ORNAMENT	𑙫
		0x1166C, // MONGOLIAN TURNED SWIRL BIRGA WITH DOUBLE ORNAMENT	𑙬
		0x1173C, // AHOM SIGN SMALL SECTION	𑜼
		0x1173D, // AHOM SIGN SECTION	𑜽
		0x1173E, // AHOM SIGN RULAI	𑜾
		0x1183B, // DOGRA ABBREVIATION SIGN	𑠻
		0x119E2, // NANDINAGARI SIGN SIDDHAM	𑧢
		0x11A3F, // ZANABAZAR SQUARE INITIAL HEAD MARK	𑨿
		0x11A40, // ZANABAZAR SQUARE CLOSING HEAD MARK	𑩀
		0x11A41, // ZANABAZAR SQUARE MARK TSHEG	𑩁
		0x11A42, // ZANABAZAR SQUARE MARK SHAD	𑩂
		0x11A43, // ZANABAZAR SQUARE MARK DOUBLE SHAD	𑩃
		0x11A44, // ZANABAZAR SQUARE MARK LONG TSHEG	𑩄
		0x11A45, // ZANABAZAR SQUARE INITIAL DOUBLE-LINED HEAD MARK	𑩅
		0x11A46, // ZANABAZAR SQUARE CLOSING DOUBLE-LINED HEAD MARK	𑩆
		0x11A9A, // SOYOMBO MARK TSHEG	𑪚
		0x11A9B, // SOYOMBO MARK SHAD	𑪛
		0x11A9C, // SOYOMBO MARK DOUBLE SHAD	𑪜
		0x11A9E, // SOYOMBO HEAD MARK WITH MOON AND SUN AND TRIPLE FLAME	𑪞
		0x11A9F, // SOYOMBO HEAD MARK WITH MOON AND SUN AND FLAME	𑪟
		0x11AA0, // SOYOMBO HEAD MARK WITH MOON AND SUN	𑪠
		0x11AA1, // SOYOMBO TERMINAL MARK-1	𑪡
		0x11AA2, // SOYOMBO TERMINAL MARK-2	𑪢
		0x11C41, // BHAIKSUKI DANDA	𑱁
		0x11C42, // BHAIKSUKI DOUBLE DANDA	𑱂
		0x11C43, // BHAIKSUKI WORD SEPARATOR	𑱃
		0x11C44, // BHAIKSUKI GAP FILLER-1	𑱄
		0x11C45, // BHAIKSUKI GAP FILLER-2	𑱅
		0x11C70, // MARCHEN HEAD MARK	𑱰
		0x11C71, // MARCHEN MARK SHAD	𑱱
		0x11EF7, // MAKASAR PASSIMBANG	𑻷
		0x11EF8, // MAKASAR END OF SECTION	𑻸
		0x11FFF, // TAMIL PUNCTUATION END OF TEXT	𑿿
		0x12470, // CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER	𒑰
		0x12471, // CUNEIFORM PUNCTUATION SIGN VERTICAL COLON	𒑱
		0x12472, // CUNEIFORM PUNCTUATION SIGN DIAGONAL COLON	𒑲
		0x12473, // CUNEIFORM PUNCTUATION SIGN DIAGONAL TRICOLON	𒑳
		0x12474, // CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON	𒑴
		0x16A6E, // MRO DANDA	𖩮
		0x16A6F, // MRO DOUBLE DANDA	𖩯
		0x16AF5, // BASSA VAH FULL STOP	𖫵
		0x16B37, // PAHAWH HMONG SIGN VOS THOM	𖬷
		0x16B38, // PAHAWH HMONG SIGN VOS TSHAB CEEB	𖬸
		0x16B39, // PAHAWH HMONG SIGN CIM CHEEM	𖬹
		0x16B3A, // PAHAWH HMONG SIGN VOS THIAB	𖬺
		0x16B3B, // PAHAWH HMONG SIGN VOS FEEM	𖬻
		0x16B44, // PAHAWH HMONG SIGN XAUS	𖭄
		0x16E97, // MEDEFAIDRIN COMMA	𖺗
		0x16E98, // MEDEFAIDRIN FULL STOP	𖺘
		0x16E99, // MEDEFAIDRIN SYMBOL AIVA	𖺙
		0x16E9A, // MEDEFAIDRIN EXCLAMATION OH	𖺚
		0x16FE2, // OLD CHINESE HOOK MARK	𖿢
		0x1BC9F, // DUPLOYAN PUNCTUATION CHINOOK FULL STOP	𛲟
		0x1DA87, // SIGNWRITING COMMA	𝪇
		0x1DA88, // SIGNWRITING FULL STOP	𝪈
		0x1DA89, // SIGNWRITING SEMICOLON	𝪉
		0x1DA8A, // SIGNWRITING COLON	𝪊
		0x1DA8B, // SIGNWRITING PARENTHESIS	𝪋
		0x1E95E, // ADLAM INITIAL EXCLAMATION MARK	𞥞
		0x1E95F, // ADLAM INITIAL QUESTION MARK
	]
)
