1df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov/*
2df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov * Copyright (C) 2009 The Android Open Source Project
3df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov *
4df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov * Licensed under the Apache License, Version 2.0 (the "License");
5df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov * you may not use this file except in compliance with the License.
6df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov * You may obtain a copy of the License at
7df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov *
8df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov *      http://www.apache.org/licenses/LICENSE-2.0
9df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov *
10df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov * Unless required by applicable law or agreed to in writing, software
11df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov * distributed under the License is distributed on an "AS IS" BASIS,
12df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov * See the License for the specific language governing permissions and
14df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov * limitations under the License.
15df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov */
16df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov
17df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikovpackage com.android.internal.util;
18df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov
19df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikovimport android.text.TextUtils;
20df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikovimport android.util.Log;
21df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov
22df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikovimport java.text.Collator;
23df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikovimport java.util.ArrayList;
24df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikovimport java.util.Locale;
25df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov
26df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov/**
27df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov * An object to convert Chinese character to its corresponding pinyin string.
28df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov * For characters with multiple possible pinyin string, only one is selected
29df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov * according to collator. Polyphone is not supported in this implementation.
30df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov * This class is implemented to achieve the best runtime performance and minimum
31df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov * runtime resources with tolerable sacrifice of accuracy. This implementation
32df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov * highly depends on zh_CN ICU collation data and must be always synchronized with
33df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov * ICU.
34df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov */
35df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikovpublic class HanziToPinyin {
36df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov    private static final String TAG = "HanziToPinyin";
37df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov
38df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov    private static final char[] UNIHANS = {
39df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u5416', '\u54ce', '\u5b89', '\u80ae', '\u51f9', '\u516b', '\u63b0', '\u6273',
40df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u90a6', '\u52f9', '\u9642', '\u5954', '\u4f3b', '\u7680', '\u782d', '\u706c',
41df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u618b', '\u6c43', '\u51ab', '\u7676', '\u5cec', '\u5693', '\u5072', '\u53c2',
42df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u4ed3', '\u64a1', '\u518a', '\u5d7e', '\u564c', '\u6260', '\u62c6', '\u8fbf',
43df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u4f25', '\u6284', '\u8f66', '\u62bb', '\u9637', '\u5403', '\u5145', '\u62bd',
44df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u51fa', '\u640b', '\u5ddb', '\u5205', '\u5439', '\u65fe', '\u8e14', '\u5472',
45df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u4ece', '\u51d1', '\u7c97', '\u6c46', '\u5d14', '\u90a8', '\u6413', '\u5491',
46df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u5446', '\u4e39', '\u5f53', '\u5200', '\u6074', '\u6265', '\u706f', '\u4efe',
47df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u55f2', '\u6541', '\u5201', '\u7239', '\u4e01', '\u4e1f', '\u4e1c', '\u543a',
48df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u5262', '\u8011', '\u5796', '\u5428', '\u591a', '\u59b8', '\u5940', '\u97a5',
49df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u800c', '\u53d1', '\u5e06', '\u531a', '\u98de', '\u5206', '\u4e30', '\u8985',
50df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u4ecf', '\u57ba', '\u7d11', '\u592b', '\u7324', '\u65ee', '\u4f85', '\u5e72',
51df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u5188', '\u768b', '\u6208', '\u7ed9', '\u6839', '\u63ef', '\u55bc', '\u55f0',
52df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u5de5', '\u52fe', '\u4f30', '\u9e39', '\u4e56', '\u5173', '\u5149', '\u5f52',
53df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u4e28', '\u8b34', '\u5459', '\u598e', '\u548d', '\u4f44', '\u592f', '\u8320',
54df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u8bc3', '\u9ed2', '\u62eb', '\u4ea8', '\u53ff', '\u9f41', '\u4e4e', '\u82b1',
55df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u6000', '\u6b22', '\u5ddf', '\u7070', '\u660f', '\u5419', '\u4e0c', '\u52a0',
56df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u620b', '\u6c5f', '\u827d', '\u9636', '\u5dfe', '\u5755', '\u5182', '\u4e29',
57df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u51e5', '\u59e2', '\u5658', '\u519b', '\u5494', '\u5f00', '\u938e', '\u5ffc',
58df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u5c3b', '\u533c', '\u808e', '\u52a5', '\u7a7a', '\u62a0', '\u625d', '\u5938',
59df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u84af', '\u5bbd', '\u5321', '\u4e8f', '\u5764', '\u6269', '\u62c9', '\u4f86',
60df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u5170', '\u5577', '\u635e', '\u4ec2', '\u96f7', '\u8137', '\u68f1', '\u695e',
61df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u550e', '\u4fe9', '\u5afe', '\u826f', '\u8e7d', '\u57d3', '\u53b8', '\u62ce',
62df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u6e9c', '\u9f99', '\u5a04', '\u565c', '\u5b6a', '\u62a1', '\u9831', '\u5988',
63df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u57cb', '\u989f', '\u7264', '\u732b', '\u5445', '\u95e8', '\u6c13', '\u54aa',
64df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u5b80', '\u55b5', '\u4e5c', '\u6c11', '\u540d', '\u8c2c', '\u6478', '\u725f',
65df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u6bcd', '\u62cf', '\u8149', '\u56e1', '\u56d4', '\u5b6c', '\u8bb7', '\u5a1e',
66df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u5ae9', '\u80fd', '\u92b0', '\u62c8', '\u5a18', '\u9e1f', '\u634f', '\u56dc',
67df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u5b81', '\u599e', '\u519c', '\u7fba', '\u5974', '\u597b', '\u9ec1', '\u90cd',
68df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u5662', '\u8bb4', '\u5991', '\u62cd', '\u7705', '\u6c78', '\u629b', '\u5478',
69df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u55b7', '\u5309', '\u4e76', '\u7247', '\u527d', '\u6c15', '\u59d8', '\u4e52',
70df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u948b', '\u5256', '\u4ec6', '\u4e03', '\u6390', '\u5343', '\u545b', '\u6084',
71df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u5207', '\u4eb2', '\u9751', '\u5b86', '\u74d7', '\u533a', '\u5cd1', '\u7094',
72df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u590b', '\u5465', '\u7a63', '\u835b', '\u60f9', '\u4eba', '\u6254', '\u65e5',
73df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u620e', '\u53b9', '\u909a', '\u5827', '\u6875', '\u95f0', '\u633c', '\u4ee8',
74df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u6be2', '\u4e09', '\u6852', '\u63bb', '\u8272', '\u68ee', '\u50e7', '\u6740',
75df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u7b5b', '\u5c71', '\u4f24', '\u5f30', '\u5962', '\u7533', '\u5347', '\u5c38',
76df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u53ce', '\u4e66', '\u5237', '\u8870', '\u95e9', '\u53cc', '\u8c01', '\u542e',
77df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u8bf4', '\u53b6', '\u5fea', '\u51c1', '\u82cf', '\u72fb', '\u590a', '\u5b59',
78df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u5506', '\u4ed6', '\u5b61', '\u574d', '\u6c64', '\u5932', '\u5fd1', '\u81af',
79df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u5254', '\u5929', '\u65eb', '\u6017', '\u5385', '\u70b5', '\u5077', '\u51f8',
80df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u6e4d', '\u63a8', '\u541e', '\u8bac', '\u52b8', '\u6b6a', '\u5f2f', '\u5c23',
81df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u5371', '\u6637', '\u7fc1', '\u631d', '\u4e4c', '\u5915', '\u5477', '\u4ed9',
82df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u4e61', '\u7071', '\u4e9b', '\u5fc3', '\u5174', '\u51f6', '\u4f11', '\u620c',
83df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u5405', '\u75b6', '\u7025', '\u4e2b', '\u54bd', '\u592e', '\u5e7a', '\u503b',
84df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u4e00', '\u4e5a', '\u5e94', '\u5537', '\u4f63', '\u4f18', '\u7ea1', '\u56e6',
85df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u66f0', '\u8480', '\u5e00', '\u707d', '\u5142', '\u7242', '\u50ae', '\u556b',
86df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u9c61', '\u600e', '\u66fd', '\u5412', '\u635a', '\u6cbe', '\u5f20', '\u4f4b',
87df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u8707', '\u8d1e', '\u9eee', '\u4e4b', '\u4e2d', '\u5dde', '\u6731', '\u6293',
88df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u62fd', '\u4e13', '\u5986', '\u96b9', '\u5b92', '\u5353', '\u4ed4', '\u5b97',
89df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            '\u90b9', '\u79df', '\u5297', '\u55fa', '\u5c0a', '\u6628',
90df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        };
91df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov    private final static byte[][] PINYINS = {
92df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {65, 00, 00, 00, 00, 00, }, {65, 73, 00, 00, 00, 00, },
93df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {65, 78, 00, 00, 00, 00, }, {65, 78, 71, 00, 00, 00, },
94df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {65, 79, 00, 00, 00, 00, }, {66, 65, 00, 00, 00, 00, },
95df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {66, 65, 73, 00, 00, 00, }, {66, 65, 78, 00, 00, 00, },
96df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {66, 65, 78, 71, 00, 00, }, {66, 65, 79, 00, 00, 00, },
97df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {66, 69, 73, 00, 00, 00, }, {66, 69, 78, 00, 00, 00, },
98df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {66, 69, 78, 71, 00, 00, }, {66, 73, 00, 00, 00, 00, },
99df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {66, 73, 65, 78, 00, 00, }, {66, 73, 65, 79, 00, 00, },
100df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {66, 73, 69, 00, 00, 00, }, {66, 73, 78, 00, 00, 00, },
101df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {66, 73, 78, 71, 00, 00, }, {66, 79, 00, 00, 00, 00, },
102df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {66, 85, 00, 00, 00, 00, }, {67, 65, 00, 00, 00, 00, },
103df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {67, 65, 73, 00, 00, 00, }, {67, 65, 78, 00, 00, 00, },
104df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {67, 65, 78, 71, 00, 00, }, {67, 65, 79, 00, 00, 00, },
105df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {67, 69, 00, 00, 00, 00, }, {67, 69, 78, 00, 00, 00, },
106df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {67, 69, 78, 71, 00, 00, }, {67, 72, 65, 00, 00, 00, },
107df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {67, 72, 65, 73, 00, 00, }, {67, 72, 65, 78, 00, 00, },
108df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {67, 72, 65, 78, 71, 00, }, {67, 72, 65, 79, 00, 00, },
109df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {67, 72, 69, 00, 00, 00, }, {67, 72, 69, 78, 00, 00, },
110df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {67, 72, 69, 78, 71, 00, }, {67, 72, 73, 00, 00, 00, },
111df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {67, 72, 79, 78, 71, 00, }, {67, 72, 79, 85, 00, 00, },
112df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {67, 72, 85, 00, 00, 00, }, {67, 72, 85, 65, 73, 00, },
113df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {67, 72, 85, 65, 78, 00, }, {67, 72, 85, 65, 78, 71, },
114df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {67, 72, 85, 73, 00, 00, }, {67, 72, 85, 78, 00, 00, },
115df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {67, 72, 85, 79, 00, 00, }, {67, 73, 00, 00, 00, 00, },
116df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {67, 79, 78, 71, 00, 00, }, {67, 79, 85, 00, 00, 00, },
117df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {67, 85, 00, 00, 00, 00, }, {67, 85, 65, 78, 00, 00, },
118df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {67, 85, 73, 00, 00, 00, }, {67, 85, 78, 00, 00, 00, },
119df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {67, 85, 79, 00, 00, 00, }, {68, 65, 00, 00, 00, 00, },
120df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {68, 65, 73, 00, 00, 00, }, {68, 65, 78, 00, 00, 00, },
121df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {68, 65, 78, 71, 00, 00, }, {68, 65, 79, 00, 00, 00, },
122df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {68, 69, 00, 00, 00, 00, }, {68, 69, 78, 00, 00, 00, },
123df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {68, 69, 78, 71, 00, 00, }, {68, 73, 00, 00, 00, 00, },
124df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {68, 73, 65, 00, 00, 00, }, {68, 73, 65, 78, 00, 00, },
125df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {68, 73, 65, 79, 00, 00, }, {68, 73, 69, 00, 00, 00, },
126df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {68, 73, 78, 71, 00, 00, }, {68, 73, 85, 00, 00, 00, },
127df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {68, 79, 78, 71, 00, 00, }, {68, 79, 85, 00, 00, 00, },
128df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {68, 85, 00, 00, 00, 00, }, {68, 85, 65, 78, 00, 00, },
129df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {68, 85, 73, 00, 00, 00, }, {68, 85, 78, 00, 00, 00, },
130df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {68, 85, 79, 00, 00, 00, }, {69, 00, 00, 00, 00, 00, },
131df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {69, 78, 00, 00, 00, 00, }, {69, 78, 71, 00, 00, 00, },
132df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {69, 82, 00, 00, 00, 00, }, {70, 65, 00, 00, 00, 00, },
133df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {70, 65, 78, 00, 00, 00, }, {70, 65, 78, 71, 00, 00, },
134df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {70, 69, 73, 00, 00, 00, }, {70, 69, 78, 00, 00, 00, },
135df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {70, 69, 78, 71, 00, 00, }, {70, 73, 65, 79, 00, 00, },
136df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {70, 79, 00, 00, 00, 00, }, {70, 85, 00, 00, 00, 00, },
137df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {70, 79, 85, 00, 00, 00, }, {70, 85, 00, 00, 00, 00, },
138df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {71, 85, 73, 00, 00, 00, }, {71, 65, 00, 00, 00, 00, },
139df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {71, 65, 73, 00, 00, 00, }, {71, 65, 78, 00, 00, 00, },
140df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {71, 65, 78, 71, 00, 00, }, {71, 65, 79, 00, 00, 00, },
141df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {71, 69, 00, 00, 00, 00, }, {71, 69, 73, 00, 00, 00, },
142df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {71, 69, 78, 00, 00, 00, }, {71, 69, 78, 71, 00, 00, },
143df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {74, 73, 69, 00, 00, 00, }, {71, 69, 00, 00, 00, 00, },
144df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {71, 79, 78, 71, 00, 00, }, {71, 79, 85, 00, 00, 00, },
145df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {71, 85, 00, 00, 00, 00, }, {71, 85, 65, 00, 00, 00, },
146df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {71, 85, 65, 73, 00, 00, }, {71, 85, 65, 78, 00, 00, },
147df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {71, 85, 65, 78, 71, 00, }, {71, 85, 73, 00, 00, 00, },
148df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {71, 85, 78, 00, 00, 00, }, {71, 85, 65, 78, 00, 00, },
149df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {71, 85, 79, 00, 00, 00, }, {72, 65, 00, 00, 00, 00, },
150df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {72, 65, 73, 00, 00, 00, }, {72, 65, 78, 00, 00, 00, },
151df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {72, 65, 78, 71, 00, 00, }, {72, 65, 79, 00, 00, 00, },
152df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {72, 69, 00, 00, 00, 00, }, {72, 69, 73, 00, 00, 00, },
153df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {72, 69, 78, 00, 00, 00, }, {72, 69, 78, 71, 00, 00, },
154df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {72, 79, 78, 71, 00, 00, }, {72, 79, 85, 00, 00, 00, },
155df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {72, 85, 00, 00, 00, 00, }, {72, 85, 65, 00, 00, 00, },
156df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {72, 85, 65, 73, 00, 00, }, {72, 85, 65, 78, 00, 00, },
157df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {72, 85, 65, 78, 71, 00, }, {72, 85, 73, 00, 00, 00, },
158df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {72, 85, 78, 00, 00, 00, }, {72, 85, 79, 00, 00, 00, },
159df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {74, 73, 00, 00, 00, 00, }, {74, 73, 65, 00, 00, 00, },
160df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {74, 73, 65, 78, 00, 00, }, {74, 73, 65, 78, 71, 00, },
161df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {74, 73, 65, 79, 00, 00, }, {74, 73, 69, 00, 00, 00, },
162df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {74, 73, 78, 00, 00, 00, }, {74, 73, 78, 71, 00, 00, },
163df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {74, 73, 79, 78, 71, 00, }, {74, 73, 85, 00, 00, 00, },
164df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {74, 85, 00, 00, 00, 00, }, {74, 85, 65, 78, 00, 00, },
165df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {74, 85, 69, 00, 00, 00, }, {74, 85, 78, 00, 00, 00, },
166df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {75, 65, 00, 00, 00, 00, }, {75, 65, 73, 00, 00, 00, },
167df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {75, 65, 78, 00, 00, 00, }, {75, 65, 78, 71, 00, 00, },
168df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {75, 65, 79, 00, 00, 00, }, {75, 69, 00, 00, 00, 00, },
169df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {75, 69, 78, 00, 00, 00, }, {75, 69, 78, 71, 00, 00, },
170df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {75, 79, 78, 71, 00, 00, }, {75, 79, 85, 00, 00, 00, },
171df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {75, 85, 00, 00, 00, 00, }, {75, 85, 65, 00, 00, 00, },
172df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {75, 85, 65, 73, 00, 00, }, {75, 85, 65, 78, 00, 00, },
173df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {75, 85, 65, 78, 71, 00, }, {75, 85, 73, 00, 00, 00, },
174df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {75, 85, 78, 00, 00, 00, }, {75, 85, 79, 00, 00, 00, },
175df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {76, 65, 00, 00, 00, 00, }, {76, 65, 73, 00, 00, 00, },
176df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {76, 65, 78, 00, 00, 00, }, {76, 65, 78, 71, 00, 00, },
177df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {76, 65, 79, 00, 00, 00, }, {76, 69, 00, 00, 00, 00, },
178df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {76, 69, 73, 00, 00, 00, }, {76, 73, 00, 00, 00, 00, },
179df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {76, 73, 78, 71, 00, 00, }, {76, 69, 78, 71, 00, 00, },
180df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {76, 73, 00, 00, 00, 00, }, {76, 73, 65, 00, 00, 00, },
181df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {76, 73, 65, 78, 00, 00, }, {76, 73, 65, 78, 71, 00, },
182df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {76, 73, 65, 79, 00, 00, }, {76, 73, 69, 00, 00, 00, },
183df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {76, 73, 78, 00, 00, 00, }, {76, 73, 78, 71, 00, 00, },
184df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {76, 73, 85, 00, 00, 00, }, {76, 79, 78, 71, 00, 00, },
185df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {76, 79, 85, 00, 00, 00, }, {76, 85, 00, 00, 00, 00, },
186df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {76, 85, 65, 78, 00, 00, }, {76, 85, 78, 00, 00, 00, },
187df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {76, 85, 79, 00, 00, 00, }, {77, 65, 00, 00, 00, 00, },
188df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {77, 65, 73, 00, 00, 00, }, {77, 65, 78, 00, 00, 00, },
189df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {77, 65, 78, 71, 00, 00, }, {77, 65, 79, 00, 00, 00, },
190df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {77, 69, 73, 00, 00, 00, }, {77, 69, 78, 00, 00, 00, },
191df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {77, 69, 78, 71, 00, 00, }, {77, 73, 00, 00, 00, 00, },
192df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {77, 73, 65, 78, 00, 00, }, {77, 73, 65, 79, 00, 00, },
193df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {77, 73, 69, 00, 00, 00, }, {77, 73, 78, 00, 00, 00, },
194df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {77, 73, 78, 71, 00, 00, }, {77, 73, 85, 00, 00, 00, },
195df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {77, 79, 00, 00, 00, 00, }, {77, 79, 85, 00, 00, 00, },
196df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {77, 85, 00, 00, 00, 00, }, {78, 65, 00, 00, 00, 00, },
197df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {78, 65, 73, 00, 00, 00, }, {78, 65, 78, 00, 00, 00, },
198df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {78, 65, 78, 71, 00, 00, }, {78, 65, 79, 00, 00, 00, },
199df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {78, 69, 00, 00, 00, 00, }, {78, 69, 73, 00, 00, 00, },
200df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {78, 69, 78, 00, 00, 00, }, {78, 69, 78, 71, 00, 00, },
201df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {78, 73, 00, 00, 00, 00, }, {78, 73, 65, 78, 00, 00, },
202df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {78, 73, 65, 78, 71, 00, }, {78, 73, 65, 79, 00, 00, },
203df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {78, 73, 69, 00, 00, 00, }, {78, 73, 78, 00, 00, 00, },
204df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {78, 73, 78, 71, 00, 00, }, {78, 73, 85, 00, 00, 00, },
205df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {78, 79, 78, 71, 00, 00, }, {78, 79, 85, 00, 00, 00, },
206df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {78, 85, 00, 00, 00, 00, }, {78, 85, 65, 78, 00, 00, },
207df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {78, 85, 78, 00, 00, 00, }, {78, 85, 79, 00, 00, 00, },
208df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {79, 00, 00, 00, 00, 00, }, {79, 85, 00, 00, 00, 00, },
209df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {80, 65, 00, 00, 00, 00, }, {80, 65, 73, 00, 00, 00, },
210df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {80, 65, 78, 00, 00, 00, }, {80, 65, 78, 71, 00, 00, },
211df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {80, 65, 79, 00, 00, 00, }, {80, 69, 73, 00, 00, 00, },
212df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {80, 69, 78, 00, 00, 00, }, {80, 69, 78, 71, 00, 00, },
213df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {80, 73, 00, 00, 00, 00, }, {80, 73, 65, 78, 00, 00, },
214df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {80, 73, 65, 79, 00, 00, }, {80, 73, 69, 00, 00, 00, },
215df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {80, 73, 78, 00, 00, 00, }, {80, 73, 78, 71, 00, 00, },
216df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {80, 79, 00, 00, 00, 00, }, {80, 79, 85, 00, 00, 00, },
217df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {80, 85, 00, 00, 00, 00, }, {81, 73, 00, 00, 00, 00, },
218df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {81, 73, 65, 00, 00, 00, }, {81, 73, 65, 78, 00, 00, },
219df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {81, 73, 65, 78, 71, 00, }, {81, 73, 65, 79, 00, 00, },
220df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {81, 73, 69, 00, 00, 00, }, {81, 73, 78, 00, 00, 00, },
221df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {81, 73, 78, 71, 00, 00, }, {81, 73, 79, 78, 71, 00, },
222df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {81, 73, 85, 00, 00, 00, }, {81, 85, 00, 00, 00, 00, },
223df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {81, 85, 65, 78, 00, 00, }, {81, 85, 69, 00, 00, 00, },
224df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {81, 85, 78, 00, 00, 00, }, {82, 65, 78, 00, 00, 00, },
225df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {82, 65, 78, 71, 00, 00, }, {82, 65, 79, 00, 00, 00, },
226df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {82, 69, 00, 00, 00, 00, }, {82, 69, 78, 00, 00, 00, },
227df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {82, 69, 78, 71, 00, 00, }, {82, 73, 00, 00, 00, 00, },
228df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {82, 79, 78, 71, 00, 00, }, {82, 79, 85, 00, 00, 00, },
229df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {82, 85, 00, 00, 00, 00, }, {82, 85, 65, 78, 00, 00, },
230df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {82, 85, 73, 00, 00, 00, }, {82, 85, 78, 00, 00, 00, },
231df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {82, 85, 79, 00, 00, 00, }, {83, 65, 00, 00, 00, 00, },
232df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {83, 65, 73, 00, 00, 00, }, {83, 65, 78, 00, 00, 00, },
233df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {83, 65, 78, 71, 00, 00, }, {83, 65, 79, 00, 00, 00, },
234df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {83, 69, 00, 00, 00, 00, }, {83, 69, 78, 00, 00, 00, },
235df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {83, 69, 78, 71, 00, 00, }, {83, 72, 65, 00, 00, 00, },
236df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {83, 72, 65, 73, 00, 00, }, {83, 72, 65, 78, 00, 00, },
237df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {83, 72, 65, 78, 71, 00, }, {83, 72, 65, 79, 00, 00, },
238df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {83, 72, 69, 00, 00, 00, }, {83, 72, 69, 78, 00, 00, },
239df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {83, 72, 69, 78, 71, 00, }, {83, 72, 73, 00, 00, 00, },
240df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {83, 72, 79, 85, 00, 00, }, {83, 72, 85, 00, 00, 00, },
241df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {83, 72, 85, 65, 00, 00, }, {83, 72, 85, 65, 73, 00, },
242df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {83, 72, 85, 65, 78, 00, }, {83, 72, 85, 65, 78, 71, },
243df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {83, 72, 85, 73, 00, 00, }, {83, 72, 85, 78, 00, 00, },
244df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {83, 72, 85, 79, 00, 00, }, {83, 73, 00, 00, 00, 00, },
245df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {83, 79, 78, 71, 00, 00, }, {83, 79, 85, 00, 00, 00, },
246df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {83, 85, 00, 00, 00, 00, }, {83, 85, 65, 78, 00, 00, },
247df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {83, 85, 73, 00, 00, 00, }, {83, 85, 78, 00, 00, 00, },
248df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {83, 85, 79, 00, 00, 00, }, {84, 65, 00, 00, 00, 00, },
249df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {84, 65, 73, 00, 00, 00, }, {84, 65, 78, 00, 00, 00, },
250df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {84, 65, 78, 71, 00, 00, }, {84, 65, 79, 00, 00, 00, },
251df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {84, 69, 00, 00, 00, 00, }, {84, 69, 78, 71, 00, 00, },
252df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {84, 73, 00, 00, 00, 00, }, {84, 73, 65, 78, 00, 00, },
253df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {84, 73, 65, 79, 00, 00, }, {84, 73, 69, 00, 00, 00, },
254df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {84, 73, 78, 71, 00, 00, }, {84, 79, 78, 71, 00, 00, },
255df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {84, 79, 85, 00, 00, 00, }, {84, 85, 00, 00, 00, 00, },
256df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {84, 85, 65, 78, 00, 00, }, {84, 85, 73, 00, 00, 00, },
257df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {84, 85, 78, 00, 00, 00, }, {84, 85, 79, 00, 00, 00, },
258df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {87, 65, 00, 00, 00, 00, }, {87, 65, 73, 00, 00, 00, },
259df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {87, 65, 78, 00, 00, 00, }, {87, 65, 78, 71, 00, 00, },
260df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {87, 69, 73, 00, 00, 00, }, {87, 69, 78, 00, 00, 00, },
261df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {87, 69, 78, 71, 00, 00, }, {87, 79, 00, 00, 00, 00, },
262df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {87, 85, 00, 00, 00, 00, }, {88, 73, 00, 00, 00, 00, },
263df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {88, 73, 65, 00, 00, 00, }, {88, 73, 65, 78, 00, 00, },
264df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {88, 73, 65, 78, 71, 00, }, {88, 73, 65, 79, 00, 00, },
265df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {88, 73, 69, 00, 00, 00, }, {88, 73, 78, 00, 00, 00, },
266df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {88, 73, 78, 71, 00, 00, }, {88, 73, 79, 78, 71, 00, },
267df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {88, 73, 85, 00, 00, 00, }, {88, 85, 00, 00, 00, 00, },
268df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {88, 85, 65, 78, 00, 00, }, {88, 85, 69, 00, 00, 00, },
269df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {88, 85, 78, 00, 00, 00, }, {89, 65, 00, 00, 00, 00, },
270df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {89, 65, 78, 00, 00, 00, }, {89, 65, 78, 71, 00, 00, },
271df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {89, 65, 79, 00, 00, 00, }, {89, 69, 00, 00, 00, 00, },
272df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {89, 73, 00, 00, 00, 00, }, {89, 73, 78, 00, 00, 00, },
273df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {89, 73, 78, 71, 00, 00, }, {89, 79, 00, 00, 00, 00, },
274df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {89, 79, 78, 71, 00, 00, }, {89, 79, 85, 00, 00, 00, },
275df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {89, 85, 00, 00, 00, 00, }, {89, 85, 65, 78, 00, 00, },
276df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {89, 85, 69, 00, 00, 00, }, {89, 85, 78, 00, 00, 00, },
277df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {90, 65, 00, 00, 00, 00, }, {90, 65, 73, 00, 00, 00, },
278df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {90, 65, 78, 00, 00, 00, }, {90, 65, 78, 71, 00, 00, },
279df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {90, 65, 79, 00, 00, 00, }, {90, 69, 00, 00, 00, 00, },
280df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {90, 69, 73, 00, 00, 00, }, {90, 69, 78, 00, 00, 00, },
281df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {90, 69, 78, 71, 00, 00, }, {90, 72, 65, 00, 00, 00, },
282df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {90, 72, 65, 73, 00, 00, }, {90, 72, 65, 78, 00, 00, },
283df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {90, 72, 65, 78, 71, 00, }, {90, 72, 65, 79, 00, 00, },
284df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {90, 72, 69, 00, 00, 00, }, {90, 72, 69, 78, 00, 00, },
285df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {90, 72, 69, 78, 71, 00, }, {90, 72, 73, 00, 00, 00, },
286df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {90, 72, 79, 78, 71, 00, }, {90, 72, 79, 85, 00, 00, },
287df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {90, 72, 85, 00, 00, 00, }, {90, 72, 85, 65, 00, 00, },
288df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {90, 72, 85, 65, 73, 00, }, {90, 72, 85, 65, 78, 00, },
289df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {90, 72, 85, 65, 78, 71, }, {90, 72, 85, 73, 00, 00, },
290df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {90, 72, 85, 78, 00, 00, }, {90, 72, 85, 79, 00, 00, },
291df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {90, 73, 00, 00, 00, 00, }, {90, 79, 78, 71, 00, 00, },
292df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {90, 79, 85, 00, 00, 00, }, {90, 85, 00, 00, 00, 00, },
293df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {90, 85, 65, 78, 00, 00, }, {90, 85, 73, 00, 00, 00, },
294df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            {90, 85, 78, 00, 00, 00, }, {90, 85, 79, 00, 00, 00, },
295df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov
296df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        };
297df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov
298df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov    /** First and last Chinese character with known Pinyin according to zh collation */
2994256586663f0d045c69ea818db4893b3365b9915Bai Tao    private static final String FIRST_PINYIN_UNIHAN =  "\u5416";
3004256586663f0d045c69ea818db4893b3365b9915Bai Tao    private static final String LAST_PINYIN_UNIHAN =  "\u5497";
3014256586663f0d045c69ea818db4893b3365b9915Bai Tao    /** The first Chinese character in Unicode block */
3024256586663f0d045c69ea818db4893b3365b9915Bai Tao    private static final char FIRST_UNIHAN = '\u3400';
303df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov    private static final Collator COLLATOR = Collator.getInstance(Locale.CHINA);
304df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov
305df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov    private static HanziToPinyin sInstance;
306df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov    private final boolean mHasChinaCollator;
307df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov
308df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov    public static class Token {
309df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        /**
310df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov         * Separator between target string for each source char
311df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov         */
312df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        public static final String SEPARATOR = " ";
313df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov
3144256586663f0d045c69ea818db4893b3365b9915Bai Tao        public static final int LATIN = 1;
315df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        public static final int PINYIN = 2;
316df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        public static final int UNKNOWN = 3;
317df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov
3184256586663f0d045c69ea818db4893b3365b9915Bai Tao        public Token() {
3194256586663f0d045c69ea818db4893b3365b9915Bai Tao        }
3204256586663f0d045c69ea818db4893b3365b9915Bai Tao
3214256586663f0d045c69ea818db4893b3365b9915Bai Tao        public Token(int type, String source, String target) {
3224256586663f0d045c69ea818db4893b3365b9915Bai Tao            this.type = type;
3234256586663f0d045c69ea818db4893b3365b9915Bai Tao            this.source = source;
3244256586663f0d045c69ea818db4893b3365b9915Bai Tao            this.target = target;
3254256586663f0d045c69ea818db4893b3365b9915Bai Tao        }
326df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        /**
327df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov         * Type of this token, ASCII, PINYIN or UNKNOWN.
328df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov         */
329df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        public int type;
330df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        /**
331df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov         * Original string before translation.
332df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov         */
333df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        public String source;
334df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        /**
335df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov         * Translated string of source. For Han, target is corresponding Pinyin.
336df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov         * Otherwise target is original string in source.
337df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov         */
338df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        public String target;
339df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov    }
340df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov
341df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov    protected HanziToPinyin(boolean hasChinaCollator) {
342df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        mHasChinaCollator = hasChinaCollator;
343df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov    }
344df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov
345df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov    public static HanziToPinyin getInstance() {
346df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        synchronized(HanziToPinyin.class) {
347df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            if (sInstance != null) {
348df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov                return sInstance;
349df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            }
350df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            // Check if zh_CN collation data is available
351df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            final Locale locale[] = Collator.getAvailableLocales();
352df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            for (int i = 0; i < locale.length; i++) {
353df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov                if (locale[i].equals(Locale.CHINA)) {
354df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov                    sInstance = new HanziToPinyin(true);
355df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov                    return sInstance;
356df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov                }
357df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            }
3584256586663f0d045c69ea818db4893b3365b9915Bai Tao            Log.w(TAG, "There is no Chinese collator, HanziToPinyin is disabled");
359df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            sInstance = new HanziToPinyin(false);
360df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            return sInstance;
361df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        }
362df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov    }
363df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov
364df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov    private Token getToken(char character) {
365df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        Token token = new Token();
366df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        final String letter = Character.toString(character);
367df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        token.source = letter;
368df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        int offset = -1;
369df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        int cmp;
370df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        if (character < 256) {
3714256586663f0d045c69ea818db4893b3365b9915Bai Tao            token.type = Token.LATIN;
3724256586663f0d045c69ea818db4893b3365b9915Bai Tao            token.target = letter;
3734256586663f0d045c69ea818db4893b3365b9915Bai Tao            return token;
3744256586663f0d045c69ea818db4893b3365b9915Bai Tao        } else if (character < FIRST_UNIHAN) {
3754256586663f0d045c69ea818db4893b3365b9915Bai Tao            token.type = Token.UNKNOWN;
376df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            token.target = letter;
377df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            return token;
378df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        } else {
3794256586663f0d045c69ea818db4893b3365b9915Bai Tao            cmp = COLLATOR.compare(letter, FIRST_PINYIN_UNIHAN);
380df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            if (cmp < 0) {
381df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov                token.type = Token.UNKNOWN;
382df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov                token.target = letter;
383df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov                return token;
384df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            } else if (cmp == 0) {
385df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov                token.type = Token.PINYIN;
386df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov                offset = 0;
387df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            } else {
3884256586663f0d045c69ea818db4893b3365b9915Bai Tao                cmp = COLLATOR.compare(letter, LAST_PINYIN_UNIHAN);
389df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov                if (cmp > 0) {
390df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov                    token.type = Token.UNKNOWN;
391df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov                    token.target = letter;
392df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov                    return token;
393df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov                } else if (cmp == 0) {
394df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov                    token.type = Token.PINYIN;
395df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov                    offset = UNIHANS.length - 1;
396df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov                }
397df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            }
398df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        }
399df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov
400df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        token.type = Token.PINYIN;
401df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        if (offset < 0) {
402df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            int begin = 0;
403df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            int end = UNIHANS.length - 1;
404df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            while (begin <= end) {
405df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov                offset = (begin + end) / 2;
406df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov                final String unihan = Character.toString(UNIHANS[offset]);
407df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov                cmp = COLLATOR.compare(letter, unihan);
408df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov                if (cmp == 0) {
409df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov                    break;
410df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov                } else if (cmp > 0) {
411df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov                    begin = offset + 1;
412df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov                } else {
413df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov                    end = offset - 1;
414df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov                }
415df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            }
416df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        }
417df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        if (cmp < 0) {
418df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            offset--;
419df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        }
420df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        StringBuilder pinyin = new StringBuilder();
421df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        for (int j = 0; j < PINYINS[offset].length && PINYINS[offset][j] != 0; j++) {
422df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            pinyin.append((char)PINYINS[offset][j]);
423df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        }
424df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        token.target = pinyin.toString();
425df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        return token;
426df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov    }
427df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov
4284256586663f0d045c69ea818db4893b3365b9915Bai Tao    /**
4294256586663f0d045c69ea818db4893b3365b9915Bai Tao     * Convert the input to a array of tokens. The sequence of ASCII or Unknown
4304256586663f0d045c69ea818db4893b3365b9915Bai Tao     * characters without space will be put into a Token, One Hanzi character
4314256586663f0d045c69ea818db4893b3365b9915Bai Tao     * which has pinyin will be treated as a Token.
4324256586663f0d045c69ea818db4893b3365b9915Bai Tao     * If these is no China collator, the empty token array is returned.
4334256586663f0d045c69ea818db4893b3365b9915Bai Tao     */
434df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov    public ArrayList<Token> get(final String input) {
4354256586663f0d045c69ea818db4893b3365b9915Bai Tao        ArrayList<Token> tokens = new ArrayList<Token>();
436df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        if (!mHasChinaCollator || TextUtils.isEmpty(input)) {
4374256586663f0d045c69ea818db4893b3365b9915Bai Tao            // return empty tokens.
4384256586663f0d045c69ea818db4893b3365b9915Bai Tao            return tokens;
439df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        }
440df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        final int inputLength = input.length();
4414256586663f0d045c69ea818db4893b3365b9915Bai Tao        final StringBuilder sb = new StringBuilder();
4424256586663f0d045c69ea818db4893b3365b9915Bai Tao        int tokenType = Token.LATIN;
4434256586663f0d045c69ea818db4893b3365b9915Bai Tao        // Go through the input, create a new token when
4444256586663f0d045c69ea818db4893b3365b9915Bai Tao        // a. Token type changed
4454256586663f0d045c69ea818db4893b3365b9915Bai Tao        // b. Get the Pinyin of current charater.
4464256586663f0d045c69ea818db4893b3365b9915Bai Tao        // c. current character is space.
4474256586663f0d045c69ea818db4893b3365b9915Bai Tao        for (int i = 0; i < inputLength; i++) {
448df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            final char character = input.charAt(i);
4494256586663f0d045c69ea818db4893b3365b9915Bai Tao            if (character == ' ') {
4504256586663f0d045c69ea818db4893b3365b9915Bai Tao                if (sb.length() > 0) {
4514256586663f0d045c69ea818db4893b3365b9915Bai Tao                    addToken(sb, tokens, tokenType);
4524256586663f0d045c69ea818db4893b3365b9915Bai Tao                }
4534256586663f0d045c69ea818db4893b3365b9915Bai Tao            } else if (character < 256) {
4544256586663f0d045c69ea818db4893b3365b9915Bai Tao                if (tokenType != Token.LATIN && sb.length() > 0) {
4554256586663f0d045c69ea818db4893b3365b9915Bai Tao                    addToken(sb, tokens, tokenType);
4564256586663f0d045c69ea818db4893b3365b9915Bai Tao                }
4574256586663f0d045c69ea818db4893b3365b9915Bai Tao                tokenType = Token.LATIN;
4584256586663f0d045c69ea818db4893b3365b9915Bai Tao                sb.append(character);
4594256586663f0d045c69ea818db4893b3365b9915Bai Tao            } else if (character < FIRST_UNIHAN) {
4604256586663f0d045c69ea818db4893b3365b9915Bai Tao                if (tokenType != Token.UNKNOWN && sb.length() > 0) {
4614256586663f0d045c69ea818db4893b3365b9915Bai Tao                    addToken(sb, tokens, tokenType);
4624256586663f0d045c69ea818db4893b3365b9915Bai Tao                }
4634256586663f0d045c69ea818db4893b3365b9915Bai Tao                tokenType = Token.UNKNOWN;
4644256586663f0d045c69ea818db4893b3365b9915Bai Tao                sb.append(character);
465df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            } else {
4664256586663f0d045c69ea818db4893b3365b9915Bai Tao                Token t = getToken(character);
4674256586663f0d045c69ea818db4893b3365b9915Bai Tao                if (t.type == Token.PINYIN) {
4684256586663f0d045c69ea818db4893b3365b9915Bai Tao                    if (sb.length() > 0) {
4694256586663f0d045c69ea818db4893b3365b9915Bai Tao                        addToken(sb, tokens, tokenType);
4704256586663f0d045c69ea818db4893b3365b9915Bai Tao                    }
4714256586663f0d045c69ea818db4893b3365b9915Bai Tao                    tokens.add(t);
4724256586663f0d045c69ea818db4893b3365b9915Bai Tao                    tokenType = Token.PINYIN;
4734256586663f0d045c69ea818db4893b3365b9915Bai Tao                } else {
4744256586663f0d045c69ea818db4893b3365b9915Bai Tao                    if (tokenType != t.type && sb.length() > 0) {
4754256586663f0d045c69ea818db4893b3365b9915Bai Tao                        addToken(sb, tokens, tokenType);
4764256586663f0d045c69ea818db4893b3365b9915Bai Tao                    }
4774256586663f0d045c69ea818db4893b3365b9915Bai Tao                    tokenType = t.type;
4784256586663f0d045c69ea818db4893b3365b9915Bai Tao                    sb.append(character);
479df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov                }
480df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov            }
481df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        }
4824256586663f0d045c69ea818db4893b3365b9915Bai Tao        if (sb.length() > 0) {
4834256586663f0d045c69ea818db4893b3365b9915Bai Tao            addToken(sb, tokens, tokenType);
4844256586663f0d045c69ea818db4893b3365b9915Bai Tao        }
485df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov        return tokens;
486df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov    }
4874256586663f0d045c69ea818db4893b3365b9915Bai Tao
4884256586663f0d045c69ea818db4893b3365b9915Bai Tao    private void addToken(final StringBuilder sb, final ArrayList<Token> tokens,
4894256586663f0d045c69ea818db4893b3365b9915Bai Tao            final int tokenType) {
4904256586663f0d045c69ea818db4893b3365b9915Bai Tao        String str = sb.toString();
4914256586663f0d045c69ea818db4893b3365b9915Bai Tao        tokens.add(new Token(tokenType, str, str));
4924256586663f0d045c69ea818db4893b3365b9915Bai Tao        sb.setLength(0);
4934256586663f0d045c69ea818db4893b3365b9915Bai Tao    }
4944256586663f0d045c69ea818db4893b3365b9915Bai Tao
495df1549128f26be712c46c88202b97145275f2125Dmitri Plotnikov}
496